mirror of
https://github.com/kaspanet/kaspad.git
synced 2026-02-22 19:45:36 +00:00
Compare commits
3 Commits
v0.10.0-rc
...
ghostdagRe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16a83f9bac | ||
|
|
7d20ee6b58 | ||
|
|
1ab05c3fbc |
2
.github/workflows/go.yml
vendored
2
.github/workflows/go.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-16.04, macos-10.15, windows-2019 ]
|
||||
os: [ ubuntu-16.04, macos-10.15 ]
|
||||
name: Testing on on ${{ matrix.os }}
|
||||
steps:
|
||||
|
||||
|
||||
25
app/app.go
25
app/app.go
@@ -85,6 +85,12 @@ func (app *kaspadApp) main(startedChan chan<- struct{}) error {
|
||||
profiling.Start(app.cfg.Profile, log)
|
||||
}
|
||||
|
||||
// Perform upgrades to kaspad as new versions require it.
|
||||
if err := doUpgrades(); err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Return now if an interrupt signal was triggered.
|
||||
if signal.InterruptRequested(interrupt) {
|
||||
return nil
|
||||
@@ -157,6 +163,12 @@ func (app *kaspadApp) main(startedChan chan<- struct{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// doUpgrades performs upgrades to kaspad as new versions require it.
|
||||
// currently it's a placeholder we got from kaspad upstream, that does nothing
|
||||
func doUpgrades() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// dbPath returns the path to the block database given a database type.
|
||||
func databasePath(cfg *config.Config) string {
|
||||
return filepath.Join(cfg.AppDir, "data")
|
||||
@@ -169,17 +181,6 @@ func removeDatabase(cfg *config.Config) error {
|
||||
|
||||
func openDB(cfg *config.Config) (database.Database, error) {
|
||||
dbPath := databasePath(cfg)
|
||||
|
||||
err := checkDatabaseVersion(dbPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Infof("Loading database from '%s'", dbPath)
|
||||
db, err := ldb.NewLevelDB(dbPath, leveldbCacheSizeMiB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return db, nil
|
||||
return ldb.NewLevelDB(dbPath, leveldbCacheSizeMiB)
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ func (msg *GetInfoRequestMessage) Command() MessageCommand {
|
||||
return CmdGetInfoRequestMessage
|
||||
}
|
||||
|
||||
// NewGetInfoRequestMessage returns a instance of the message
|
||||
func NewGetInfoRequestMessage() *GetInfoRequestMessage {
|
||||
// NewGeInfoRequestMessage returns a instance of the message
|
||||
func NewGeInfoRequestMessage() *GetInfoRequestMessage {
|
||||
return &GetInfoRequestMessage{}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,19 +4,23 @@ import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/utxoindex"
|
||||
|
||||
infrastructuredatabase "github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain"
|
||||
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol"
|
||||
"github.com/kaspanet/kaspad/app/rpc"
|
||||
"github.com/kaspanet/kaspad/domain"
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/utxoindex"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
infrastructuredatabase "github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/dnsseed"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
@@ -78,13 +82,7 @@ func (a *ComponentManager) Stop() {
|
||||
func NewComponentManager(cfg *config.Config, db infrastructuredatabase.Database, interrupt chan<- struct{}) (
|
||||
*ComponentManager, error) {
|
||||
|
||||
consensusConfig := consensus.Config{
|
||||
Params: *cfg.ActiveNetParams,
|
||||
IsArchival: cfg.IsArchivalNode,
|
||||
EnableSanityCheckPruningUTXOSet: cfg.EnableSanityCheckPruningUTXOSet,
|
||||
}
|
||||
|
||||
domain, err := domain.New(&consensusConfig, db)
|
||||
domain, err := domain.New(cfg.ActiveNetParams, db, cfg.IsArchivalNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const currentDatabaseVersion = 1
|
||||
|
||||
func checkDatabaseVersion(dbPath string) (err error) {
|
||||
versionFileName := versionFilePath(dbPath)
|
||||
|
||||
versionBytes, err := os.ReadFile(versionFileName)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) { // If version file doesn't exist, we assume that the database is new
|
||||
return createDatabaseVersionFile(dbPath, versionFileName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
databaseVersion, err := strconv.Atoi(string(versionBytes))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if databaseVersion != currentDatabaseVersion {
|
||||
// TODO: Once there's more then one database version, it might make sense to add upgrade logic at this point
|
||||
return errors.Errorf("Invalid database version %d. Expected version: %d", databaseVersion, currentDatabaseVersion)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createDatabaseVersionFile(dbPath string, versionFileName string) error {
|
||||
err := os.MkdirAll(dbPath, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
versionFile, err := os.Create(versionFileName)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer versionFile.Close()
|
||||
|
||||
versionString := strconv.Itoa(currentDatabaseVersion)
|
||||
_, err = versionFile.Write([]byte(versionString))
|
||||
return err
|
||||
}
|
||||
|
||||
func versionFilePath(dbPath string) string {
|
||||
dbVersionFileName := path.Join(dbPath, "version")
|
||||
return dbVersionFileName
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/blockrelay"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/domain"
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/blockheader"
|
||||
@@ -1497,7 +1496,7 @@ func TestHandleRelayInvs(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
for _, test := range tests {
|
||||
|
||||
// This is done to avoid race condition
|
||||
@@ -1512,7 +1511,7 @@ func TestHandleRelayInvs(t *testing.T) {
|
||||
errChan := make(chan error)
|
||||
context := &fakeRelayInvsContext{
|
||||
testName: test.name,
|
||||
params: &consensusConfig.Params,
|
||||
params: params,
|
||||
finishedIBD: make(chan struct{}),
|
||||
|
||||
trySetIBDRunningResponse: true,
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/addressexchange"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type fakeReceiveAddressesContext struct{}
|
||||
@@ -20,7 +19,7 @@ func (f fakeReceiveAddressesContext) AddressManager() *addressmanager.AddressMan
|
||||
}
|
||||
|
||||
func TestReceiveAddressesErrors(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
incomingRoute := router.NewRoute()
|
||||
outgoingRoute := router.NewRoute()
|
||||
peer := peerpkg.New(nil)
|
||||
|
||||
@@ -2,11 +2,10 @@ package rpccontext
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
difficultyPackage "github.com/kaspanet/kaspad/util/difficulty"
|
||||
"github.com/pkg/errors"
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
||||
|
||||
@@ -63,15 +62,12 @@ func (ctx *Context) PopulateBlockWithVerboseData(block *appmessage.RPCBlock, dom
|
||||
}
|
||||
|
||||
block.VerboseData = &appmessage.RPCBlockVerboseData{
|
||||
Hash: blockHash.String(),
|
||||
Difficulty: ctx.GetDifficultyRatio(domainBlockHeader.Bits(), ctx.Config.ActiveNetParams),
|
||||
ChildrenHashes: hashes.ToStrings(childrenHashes),
|
||||
IsHeaderOnly: blockInfo.BlockStatus == externalapi.StatusHeaderOnly,
|
||||
BlueScore: blockInfo.BlueScore,
|
||||
}
|
||||
// selectedParentHash will be nil in the genesis block
|
||||
if selectedParentHash != nil {
|
||||
block.VerboseData.SelectedParentHash = selectedParentHash.String()
|
||||
Hash: blockHash.String(),
|
||||
Difficulty: ctx.GetDifficultyRatio(domainBlockHeader.Bits(), ctx.Config.ActiveNetParams),
|
||||
ChildrenHashes: hashes.ToStrings(childrenHashes),
|
||||
SelectedParentHash: selectedParentHash.String(),
|
||||
IsHeaderOnly: blockInfo.BlockStatus == externalapi.StatusHeaderOnly,
|
||||
BlueScore: blockInfo.BlueScore,
|
||||
}
|
||||
|
||||
if blockInfo.BlockStatus == externalapi.StatusHeaderOnly {
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
)
|
||||
@@ -27,18 +28,18 @@ func (d fakeDomain) Consensus() externalapi.Consensus { return d }
|
||||
func (d fakeDomain) MiningManager() miningmanager.MiningManager { return nil }
|
||||
|
||||
func TestHandleGetBlocks(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
stagingArea := model.NewStagingArea()
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestHandleGetBlocks")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestHandleGetBlocks")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
fakeContext := rpccontext.Context{
|
||||
Config: &config.Config{Flags: &config.Flags{NetworkFlags: config.NetworkFlags{ActiveNetParams: &consensusConfig.Params}}},
|
||||
Config: &config.Config{Flags: &config.Flags{NetworkFlags: config.NetworkFlags{ActiveNetParams: params}}},
|
||||
Domain: fakeDomain{tc},
|
||||
}
|
||||
|
||||
@@ -80,7 +81,7 @@ func TestHandleGetBlocks(t *testing.T) {
|
||||
// \ | /
|
||||
// etc.
|
||||
expectedOrder := make([]*externalapi.DomainHash, 0, 40)
|
||||
mergingBlock := consensusConfig.GenesisHash
|
||||
mergingBlock := params.GenesisHash
|
||||
for i := 0; i < 10; i++ {
|
||||
splitBlocks := make([]*externalapi.DomainHash, 0, 3)
|
||||
for j := 0; j < 3; j++ {
|
||||
@@ -133,13 +134,13 @@ func TestHandleGetBlocks(t *testing.T) {
|
||||
virtualSelectedParent, actualBlocks.BlockHashes)
|
||||
}
|
||||
|
||||
expectedOrder = append([]*externalapi.DomainHash{consensusConfig.GenesisHash}, expectedOrder...)
|
||||
expectedOrder = append([]*externalapi.DomainHash{params.GenesisHash}, expectedOrder...)
|
||||
actualOrder := getBlocks(nil)
|
||||
if !reflect.DeepEqual(actualOrder.BlockHashes, hashes.ToStrings(expectedOrder)) {
|
||||
t.Fatalf("TestHandleGetBlocks \nexpected: %v \nactual:\n%v", expectedOrder, actualOrder.BlockHashes)
|
||||
}
|
||||
|
||||
requestAllExplictly := getBlocks(consensusConfig.GenesisHash)
|
||||
requestAllExplictly := getBlocks(params.GenesisHash)
|
||||
if !reflect.DeepEqual(requestAllExplictly.BlockHashes, hashes.ToStrings(expectedOrder)) {
|
||||
t.Fatalf("TestHandleGetBlocks \nexpected: \n%v\n. actual:\n%v", expectedOrder, requestAllExplictly.BlockHashes)
|
||||
}
|
||||
|
||||
@@ -6,14 +6,18 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspaminer/templatemanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/pow"
|
||||
"github.com/kaspanet/kaspad/util/difficulty"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
@@ -14,7 +13,7 @@ func balance(conf *balanceConfig) error {
|
||||
return err
|
||||
}
|
||||
|
||||
keysFile, err := keys.ReadKeysFile(conf.NetParams(), conf.KeysFile)
|
||||
keysFile, err := keys.ReadKeysFile(conf.KeysFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,11 +4,10 @@ import (
|
||||
"bufio"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
||||
"github.com/pkg/errors"
|
||||
"os"
|
||||
)
|
||||
|
||||
func create(conf *createConfig) error {
|
||||
@@ -50,13 +49,12 @@ func create(conf *createConfig) error {
|
||||
publicKeys = append(publicKeys, publicKey)
|
||||
}
|
||||
|
||||
err = keys.WriteKeysFile(
|
||||
conf.NetParams(), conf.KeysFile, encryptedPrivateKeys, publicKeys, conf.MinimumSignatures, conf.ECDSA)
|
||||
err = keys.WriteKeysFile(conf.KeysFile, encryptedPrivateKeys, publicKeys, conf.MinimumSignatures, conf.ECDSA)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keysFile, err := keys.ReadKeysFile(conf.NetParams(), conf.KeysFile)
|
||||
keysFile, err := keys.ReadKeysFile(conf.KeysFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -3,14 +3,13 @@ package main
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
)
|
||||
|
||||
func createUnsignedTransaction(conf *createUnsignedTransactionConfig) error {
|
||||
keysFile, err := keys.ReadKeysFile(conf.NetParams(), conf.KeysFile)
|
||||
keysFile, err := keys.ReadKeysFile(conf.KeysFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -3,11 +3,10 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
||||
"github.com/pkg/errors"
|
||||
"os"
|
||||
)
|
||||
|
||||
func dumpUnencryptedData(conf *dumpUnencryptedDataConfig) error {
|
||||
@@ -16,7 +15,7 @@ func dumpUnencryptedData(conf *dumpUnencryptedDataConfig) error {
|
||||
return err
|
||||
}
|
||||
|
||||
keysFile, err := keys.ReadKeysFile(conf.NetParams(), conf.KeysFile)
|
||||
keysFile, err := keys.ReadKeysFile(conf.KeysFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
// getPassword was adapted from https://gist.github.com/jlinoff/e8e26b4ffa38d379c7f1891fd174a6d0#file-getpassword2-go
|
||||
func getPassword(prompt string) []byte {
|
||||
// Get the initial state of the terminal.
|
||||
initialTermState, e1 := term.GetState(int(syscall.Stdin))
|
||||
initialTermState, e1 := term.GetState(syscall.Stdin)
|
||||
if e1 != nil {
|
||||
panic(e1)
|
||||
}
|
||||
@@ -22,13 +22,13 @@ func getPassword(prompt string) []byte {
|
||||
signal.Notify(c, os.Interrupt, os.Kill)
|
||||
go func() {
|
||||
<-c
|
||||
_ = term.Restore(int(syscall.Stdin), initialTermState)
|
||||
_ = term.Restore(syscall.Stdin, initialTermState)
|
||||
os.Exit(1)
|
||||
}()
|
||||
|
||||
// Now get the password.
|
||||
fmt.Print(prompt)
|
||||
p, err := term.ReadPassword(int(syscall.Stdin))
|
||||
p, err := term.ReadPassword(syscall.Stdin)
|
||||
fmt.Println()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
@@ -6,25 +6,20 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/crypto/argon2"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultAppDir = util.AppDir("kaspawallet", false)
|
||||
defaultAppDir = util.AppDir("kaspawallet", false)
|
||||
defaultKeysFile = filepath.Join(defaultAppDir, "keys.json")
|
||||
)
|
||||
|
||||
func defaultKeysFile(netParams *dagconfig.Params) string {
|
||||
return filepath.Join(defaultAppDir, netParams.Name, "keys.json")
|
||||
}
|
||||
|
||||
type encryptedPrivateKeyJSON struct {
|
||||
Cipher string `json:"cipher"`
|
||||
Salt string `json:"salt"`
|
||||
@@ -124,9 +119,9 @@ func (d *Data) DecryptPrivateKeys() ([][]byte, error) {
|
||||
}
|
||||
|
||||
// ReadKeysFile returns the data related to the keys file
|
||||
func ReadKeysFile(netParams *dagconfig.Params, path string) (*Data, error) {
|
||||
func ReadKeysFile(path string) (*Data, error) {
|
||||
if path == "" {
|
||||
path = defaultKeysFile(netParams)
|
||||
path = defaultKeysFile
|
||||
}
|
||||
|
||||
file, err := os.Open(path)
|
||||
@@ -162,7 +157,7 @@ func createFileDirectoryIfDoesntExist(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return os.MkdirAll(dir, 0700)
|
||||
return os.MkdirAll(dir, 0600)
|
||||
}
|
||||
|
||||
func pathExists(path string) (bool, error) {
|
||||
@@ -181,11 +176,13 @@ func pathExists(path string) (bool, error) {
|
||||
}
|
||||
|
||||
// WriteKeysFile writes a keys file with the given data
|
||||
func WriteKeysFile(netParams *dagconfig.Params, path string, encryptedPrivateKeys []*EncryptedPrivateKey,
|
||||
publicKeys [][]byte, minimumSignatures uint32, ecdsa bool) error {
|
||||
|
||||
func WriteKeysFile(path string,
|
||||
encryptedPrivateKeys []*EncryptedPrivateKey,
|
||||
publicKeys [][]byte,
|
||||
minimumSignatures uint32,
|
||||
ecdsa bool) error {
|
||||
if path == "" {
|
||||
path = defaultKeysFile(netParams)
|
||||
path = defaultKeysFile
|
||||
}
|
||||
|
||||
exists, err := pathExists(path)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -25,10 +26,10 @@ func forSchnorrAndECDSA(t *testing.T, testFunc func(t *testing.T, ecdsa bool)) {
|
||||
}
|
||||
|
||||
func TestMultisig(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
forSchnorrAndECDSA(t, func(t *testing.T, ecdsa bool) {
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
tc, teardown, err := consensus.NewFactory().NewTestConsensus(consensusConfig, "TestMultisig")
|
||||
params.BlockCoinbaseMaturity = 0
|
||||
tc, teardown, err := consensus.NewFactory().NewTestConsensus(params, false, "TestMultisig")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tc: %+v", err)
|
||||
}
|
||||
@@ -45,7 +46,7 @@ func TestMultisig(t *testing.T) {
|
||||
}
|
||||
|
||||
const minimumSignatures = 2
|
||||
address, err := libkaspawallet.Address(&consensusConfig.Params, publicKeys, minimumSignatures, ecdsa)
|
||||
address, err := libkaspawallet.Address(params, publicKeys, minimumSignatures, ecdsa)
|
||||
if err != nil {
|
||||
t.Fatalf("Address: %+v", err)
|
||||
}
|
||||
@@ -64,7 +65,7 @@ func TestMultisig(t *testing.T) {
|
||||
ExtraData: nil,
|
||||
}
|
||||
|
||||
fundingBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, coinbaseData, nil)
|
||||
fundingBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, coinbaseData, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -169,10 +170,10 @@ func TestMultisig(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestP2PK(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
forSchnorrAndECDSA(t, func(t *testing.T, ecdsa bool) {
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
tc, teardown, err := consensus.NewFactory().NewTestConsensus(consensusConfig, "TestMultisig")
|
||||
params.BlockCoinbaseMaturity = 0
|
||||
tc, teardown, err := consensus.NewFactory().NewTestConsensus(params, false, "TestMultisig")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tc: %+v", err)
|
||||
}
|
||||
@@ -189,7 +190,7 @@ func TestP2PK(t *testing.T) {
|
||||
}
|
||||
|
||||
const minimumSignatures = 1
|
||||
address, err := libkaspawallet.Address(&consensusConfig.Params, publicKeys, minimumSignatures, ecdsa)
|
||||
address, err := libkaspawallet.Address(params, publicKeys, minimumSignatures, ecdsa)
|
||||
if err != nil {
|
||||
t.Fatalf("Address: %+v", err)
|
||||
}
|
||||
@@ -214,7 +215,7 @@ func TestP2PK(t *testing.T) {
|
||||
ExtraData: nil,
|
||||
}
|
||||
|
||||
fundingBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, coinbaseData, nil)
|
||||
fundingBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, coinbaseData, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
||||
utxopkg "github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
@@ -18,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func send(conf *sendConfig) error {
|
||||
keysFile, err := keys.ReadKeysFile(conf.NetParams(), conf.KeysFile)
|
||||
keysFile, err := keys.ReadKeysFile(conf.KeysFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,13 +2,12 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
||||
)
|
||||
|
||||
func showAddress(conf *showAddressConfig) error {
|
||||
keysFile, err := keys.ReadKeysFile(conf.NetParams(), conf.KeysFile)
|
||||
keysFile, err := keys.ReadKeysFile(conf.KeysFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -3,13 +3,12 @@ package main
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
||||
)
|
||||
|
||||
func sign(conf *signConfig) error {
|
||||
keysFile, err := keys.ReadKeysFile(conf.NetParams(), conf.KeysFile)
|
||||
keysFile, err := keys.ReadKeysFile(conf.KeysFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
package consensus_test
|
||||
package consensus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestConsensus_GetBlockInfo(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
factory := consensus.NewFactory()
|
||||
consensus, teardown, err := factory.NewTestConsensus(consensusConfig, "TestConsensus_GetBlockInfo")
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := NewFactory()
|
||||
consensus, teardown, err := factory.NewTestConsensus(params, false, "TestConsensus_GetBlockInfo")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
invalidBlock, _, err := consensus.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
invalidBlock, _, err := consensus.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@ import (
|
||||
type pruningStagingShard struct {
|
||||
store *pruningStore
|
||||
|
||||
currentPruningPoint *externalapi.DomainHash
|
||||
previousPruningPoint *externalapi.DomainHash
|
||||
newPruningPoint *externalapi.DomainHash
|
||||
newPruningPointCandidate *externalapi.DomainHash
|
||||
startUpdatingPruningPointUTXOSet bool
|
||||
}
|
||||
@@ -18,8 +17,7 @@ func (ps *pruningStore) stagingShard(stagingArea *model.StagingArea) *pruningSta
|
||||
return stagingArea.GetOrCreateShard(model.StagingShardIDPruning, func() model.StagingShard {
|
||||
return &pruningStagingShard{
|
||||
store: ps,
|
||||
currentPruningPoint: nil,
|
||||
previousPruningPoint: nil,
|
||||
newPruningPoint: nil,
|
||||
newPruningPointCandidate: nil,
|
||||
startUpdatingPruningPointUTXOSet: false,
|
||||
}
|
||||
@@ -27,8 +25,8 @@ func (ps *pruningStore) stagingShard(stagingArea *model.StagingArea) *pruningSta
|
||||
}
|
||||
|
||||
func (mss *pruningStagingShard) Commit(dbTx model.DBTransaction) error {
|
||||
if mss.currentPruningPoint != nil {
|
||||
pruningPointBytes, err := mss.store.serializeHash(mss.currentPruningPoint)
|
||||
if mss.newPruningPoint != nil {
|
||||
pruningPointBytes, err := mss.store.serializeHash(mss.newPruningPoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -36,19 +34,7 @@ func (mss *pruningStagingShard) Commit(dbTx model.DBTransaction) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mss.store.pruningPointCache = mss.currentPruningPoint
|
||||
}
|
||||
|
||||
if mss.previousPruningPoint != nil {
|
||||
oldPruningPointBytes, err := mss.store.serializeHash(mss.previousPruningPoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dbTx.Put(previousPruningBlockHashKey, oldPruningPointBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mss.store.oldPruningPointCache = mss.previousPruningPoint
|
||||
mss.store.pruningPointCache = mss.newPruningPoint
|
||||
}
|
||||
|
||||
if mss.newPruningPointCandidate != nil {
|
||||
@@ -74,5 +60,5 @@ func (mss *pruningStagingShard) Commit(dbTx model.DBTransaction) error {
|
||||
}
|
||||
|
||||
func (mss *pruningStagingShard) isStaged() bool {
|
||||
return mss.currentPruningPoint != nil || mss.newPruningPointCandidate != nil || mss.previousPruningPoint != nil || mss.startUpdatingPruningPointUTXOSet
|
||||
return mss.newPruningPoint != nil || mss.startUpdatingPruningPointUTXOSet
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
)
|
||||
|
||||
var pruningBlockHashKey = database.MakeBucket(nil).Key([]byte("pruning-block-hash"))
|
||||
var previousPruningBlockHashKey = database.MakeBucket(nil).Key([]byte("previous-pruning-block-hash"))
|
||||
var candidatePruningPointHashKey = database.MakeBucket(nil).Key([]byte("candidate-pruning-point-hash"))
|
||||
var pruningPointUTXOSetBucket = database.MakeBucket([]byte("pruning-point-utxo-set"))
|
||||
var updatingPruningPointUTXOSetKey = database.MakeBucket(nil).Key([]byte("updating-pruning-point-utxo-set"))
|
||||
@@ -17,7 +16,6 @@ var updatingPruningPointUTXOSetKey = database.MakeBucket(nil).Key([]byte("updati
|
||||
// pruningStore represents a store for the current pruning state
|
||||
type pruningStore struct {
|
||||
pruningPointCache *externalapi.DomainHash
|
||||
oldPruningPointCache *externalapi.DomainHash
|
||||
pruningPointCandidateCache *externalapi.DomainHash
|
||||
}
|
||||
|
||||
@@ -74,56 +72,54 @@ func (ps *pruningStore) HasPruningPointCandidate(dbContext model.DBReader, stagi
|
||||
func (ps *pruningStore) StagePruningPoint(stagingArea *model.StagingArea, pruningPointBlockHash *externalapi.DomainHash) {
|
||||
stagingShard := ps.stagingShard(stagingArea)
|
||||
|
||||
stagingShard.currentPruningPoint = pruningPointBlockHash
|
||||
}
|
||||
|
||||
func (ps *pruningStore) StagePreviousPruningPoint(stagingArea *model.StagingArea, oldPruningPointBlockHash *externalapi.DomainHash) {
|
||||
stagingShard := ps.stagingShard(stagingArea)
|
||||
stagingShard.previousPruningPoint = oldPruningPointBlockHash
|
||||
stagingShard.newPruningPoint = pruningPointBlockHash
|
||||
}
|
||||
|
||||
func (ps *pruningStore) IsStaged(stagingArea *model.StagingArea) bool {
|
||||
return ps.stagingShard(stagingArea).isStaged()
|
||||
}
|
||||
|
||||
func (ps *pruningStore) UpdatePruningPointUTXOSet(dbContext model.DBWriter, diff externalapi.UTXODiff) error {
|
||||
toRemoveIterator := diff.ToRemove().Iterator()
|
||||
defer toRemoveIterator.Close()
|
||||
for ok := toRemoveIterator.First(); ok; ok = toRemoveIterator.Next() {
|
||||
toRemoveOutpoint, _, err := toRemoveIterator.Get()
|
||||
func (ps *pruningStore) UpdatePruningPointUTXOSet(dbContext model.DBWriter,
|
||||
utxoSetIterator externalapi.ReadOnlyUTXOSetIterator) error {
|
||||
|
||||
// Delete all the old UTXOs from the database
|
||||
deleteCursor, err := dbContext.Cursor(pruningPointUTXOSetBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer deleteCursor.Close()
|
||||
for ok := deleteCursor.First(); ok; ok = deleteCursor.Next() {
|
||||
key, err := deleteCursor.Key()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
serializedOutpoint, err := serializeOutpoint(toRemoveOutpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dbContext.Delete(pruningPointUTXOSetBucket.Key(serializedOutpoint))
|
||||
err = dbContext.Delete(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
toAddIterator := diff.ToAdd().Iterator()
|
||||
defer toAddIterator.Close()
|
||||
for ok := toAddIterator.First(); ok; ok = toAddIterator.Next() {
|
||||
toAddOutpoint, entry, err := toAddIterator.Get()
|
||||
// Insert all the new UTXOs into the database
|
||||
for ok := utxoSetIterator.First(); ok; ok = utxoSetIterator.Next() {
|
||||
outpoint, entry, err := utxoSetIterator.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
serializedOutpoint, err := serializeOutpoint(toAddOutpoint)
|
||||
serializedOutpoint, err := serializeOutpoint(outpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := pruningPointUTXOSetBucket.Key(serializedOutpoint)
|
||||
serializedUTXOEntry, err := serializeUTXOEntry(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dbContext.Put(pruningPointUTXOSetBucket.Key(serializedOutpoint), serializedUTXOEntry)
|
||||
err = dbContext.Put(key, serializedUTXOEntry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -131,8 +127,8 @@ func (ps *pruningStore) UpdatePruningPointUTXOSet(dbContext model.DBWriter, diff
|
||||
func (ps *pruningStore) PruningPoint(dbContext model.DBReader, stagingArea *model.StagingArea) (*externalapi.DomainHash, error) {
|
||||
stagingShard := ps.stagingShard(stagingArea)
|
||||
|
||||
if stagingShard.currentPruningPoint != nil {
|
||||
return stagingShard.currentPruningPoint, nil
|
||||
if stagingShard.newPruningPoint != nil {
|
||||
return stagingShard.newPruningPoint, nil
|
||||
}
|
||||
|
||||
if ps.pruningPointCache != nil {
|
||||
@@ -152,30 +148,6 @@ func (ps *pruningStore) PruningPoint(dbContext model.DBReader, stagingArea *mode
|
||||
return pruningPoint, nil
|
||||
}
|
||||
|
||||
// OldPruningPoint returns the pruning point *before* the current one
|
||||
func (ps *pruningStore) PreviousPruningPoint(dbContext model.DBReader, stagingArea *model.StagingArea) (*externalapi.DomainHash, error) {
|
||||
stagingShard := ps.stagingShard(stagingArea)
|
||||
|
||||
if stagingShard.previousPruningPoint != nil {
|
||||
return stagingShard.previousPruningPoint, nil
|
||||
}
|
||||
if ps.oldPruningPointCache != nil {
|
||||
return ps.oldPruningPointCache, nil
|
||||
}
|
||||
|
||||
oldPruningPointBytes, err := dbContext.Get(previousPruningBlockHashKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oldPruningPoint, err := ps.deserializePruningPoint(oldPruningPointBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ps.oldPruningPointCache = oldPruningPoint
|
||||
return oldPruningPoint, nil
|
||||
}
|
||||
|
||||
func (ps *pruningStore) serializeHash(hash *externalapi.DomainHash) ([]byte, error) {
|
||||
return proto.Marshal(serialization.DomainHashToDbHash(hash))
|
||||
}
|
||||
@@ -193,7 +165,7 @@ func (ps *pruningStore) deserializePruningPoint(pruningPointBytes []byte) (*exte
|
||||
func (ps *pruningStore) HasPruningPoint(dbContext model.DBReader, stagingArea *model.StagingArea) (bool, error) {
|
||||
stagingShard := ps.stagingShard(stagingArea)
|
||||
|
||||
if stagingShard.currentPruningPoint != nil {
|
||||
if stagingShard.newPruningPoint != nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -204,14 +176,6 @@ func (ps *pruningStore) HasPruningPoint(dbContext model.DBReader, stagingArea *m
|
||||
return dbContext.Has(pruningBlockHashKey)
|
||||
}
|
||||
|
||||
func (ps *pruningStore) PruningPointUTXOIterator(dbContext model.DBReader) (externalapi.ReadOnlyUTXOSetIterator, error) {
|
||||
cursor, err := dbContext.Cursor(pruningPointUTXOSetBucket)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ps.newCursorUTXOSetIterator(cursor), nil
|
||||
}
|
||||
|
||||
func (ps *pruningStore) PruningPointUTXOs(dbContext model.DBReader,
|
||||
fromOutpoint *externalapi.DomainOutpoint, limit int) ([]*externalapi.OutpointAndUTXOEntryPair, error) {
|
||||
|
||||
|
||||
@@ -28,9 +28,7 @@ func New(cacheSize int, preallocate bool) model.UTXODiffStore {
|
||||
}
|
||||
|
||||
// Stage stages the given utxoDiff for the given blockHash
|
||||
func (uds *utxoDiffStore) Stage(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash,
|
||||
utxoDiff externalapi.UTXODiff, utxoDiffChild *externalapi.DomainHash) {
|
||||
|
||||
func (uds *utxoDiffStore) Stage(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash, utxoDiff externalapi.UTXODiff, utxoDiffChild *externalapi.DomainHash) {
|
||||
stagingShard := uds.stagingShard(stagingArea)
|
||||
|
||||
stagingShard.utxoDiffToAdd[*blockHash] = utxoDiff
|
||||
|
||||
@@ -5,6 +5,13 @@ import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
daablocksstore "github.com/kaspanet/kaspad/domain/consensus/datastructures/daablocksstore"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/headersselectedchainstore"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/dagtraversalmanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/finalitymanager"
|
||||
|
||||
consensusdatabase "github.com/kaspanet/kaspad/domain/consensus/database"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/acceptancedatastore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/blockheaderstore"
|
||||
@@ -12,10 +19,8 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/blockstatusstore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/blockstore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/consensusstatestore"
|
||||
daablocksstore "github.com/kaspanet/kaspad/domain/consensus/datastructures/daablocksstore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/finalitystore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/ghostdagdatastore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/headersselectedchainstore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/headersselectedtipstore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/multisetstore"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/datastructures/pruningstore"
|
||||
@@ -29,9 +34,7 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/coinbasemanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/consensusstatemanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/dagtopologymanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/dagtraversalmanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/difficultymanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/finalitymanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/headersselectedtipmanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/mergedepthmanager"
|
||||
@@ -51,20 +54,11 @@ const (
|
||||
defaultTestPreallocateCaches = false
|
||||
)
|
||||
|
||||
// Config is the full config required to run consensus
|
||||
type Config struct {
|
||||
dagconfig.Params
|
||||
// IsArchival tells the consensus if it should not prune old blocks
|
||||
IsArchival bool
|
||||
// EnableSanityCheckPruningUTXOSet checks the full pruning point utxo set against the commitment at every pruning movement
|
||||
EnableSanityCheckPruningUTXOSet bool
|
||||
}
|
||||
|
||||
// Factory instantiates new Consensuses
|
||||
type Factory interface {
|
||||
NewConsensus(config *Config, db infrastructuredatabase.Database) (
|
||||
NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database, isArchivalNode bool) (
|
||||
externalapi.Consensus, error)
|
||||
NewTestConsensus(config *Config, testName string) (
|
||||
NewTestConsensus(dagParams *dagconfig.Params, isArchivalNode bool, testName string) (
|
||||
tc testapi.TestConsensus, teardown func(keepDataDir bool), err error)
|
||||
|
||||
SetTestDataDir(dataDir string)
|
||||
@@ -94,12 +88,12 @@ func NewFactory() Factory {
|
||||
}
|
||||
|
||||
// NewConsensus instantiates a new Consensus
|
||||
func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Database) (
|
||||
func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database, isArchivalNode bool) (
|
||||
externalapi.Consensus, error) {
|
||||
|
||||
dbManager := consensusdatabase.New(db)
|
||||
|
||||
pruningWindowSizeForCaches := int(config.PruningDepth())
|
||||
pruningWindowSizeForCaches := int(dagParams.PruningDepth())
|
||||
|
||||
var preallocateCaches bool
|
||||
if f.preallocateCaches != nil {
|
||||
@@ -110,7 +104,7 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
||||
|
||||
// This is used for caches that are used as part of deletePastBlocks that need to traverse until
|
||||
// the previous pruning point.
|
||||
pruningWindowSizePlusFinalityDepthForCache := int(config.PruningDepth() + config.FinalityDepth())
|
||||
pruningWindowSizePlusFinalityDepthForCache := int(dagParams.PruningDepth() + dagParams.FinalityDepth())
|
||||
|
||||
// Data Structures
|
||||
acceptanceDataStore := acceptancedatastore.New(200, preallocateCaches)
|
||||
@@ -135,15 +129,15 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
||||
// a single DifficultyAdjustmentWindow. To alleviate this problem we make sure that the cache size is at least
|
||||
// dagParams.DifficultyAdjustmentWindowSize
|
||||
ghostdagDataCacheSize := pruningWindowSizeForCaches
|
||||
if ghostdagDataCacheSize < config.DifficultyAdjustmentWindowSize {
|
||||
ghostdagDataCacheSize = config.DifficultyAdjustmentWindowSize
|
||||
if ghostdagDataCacheSize < dagParams.DifficultyAdjustmentWindowSize {
|
||||
ghostdagDataCacheSize = dagParams.DifficultyAdjustmentWindowSize
|
||||
}
|
||||
ghostdagDataStore := ghostdagdatastore.New(ghostdagDataCacheSize, preallocateCaches)
|
||||
|
||||
headersSelectedTipStore := headersselectedtipstore.New()
|
||||
finalityStore := finalitystore.New(200, preallocateCaches)
|
||||
headersSelectedChainStore := headersselectedchainstore.New(pruningWindowSizeForCaches, preallocateCaches)
|
||||
daaBlocksStore := daablocksstore.New(pruningWindowSizeForCaches, int(config.FinalityDepth()), preallocateCaches)
|
||||
daaBlocksStore := daablocksstore.New(pruningWindowSizeForCaches, int(dagParams.FinalityDepth()), preallocateCaches)
|
||||
|
||||
// Processes
|
||||
reachabilityManager := reachabilitymanager.New(
|
||||
@@ -160,7 +154,7 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
||||
dagTopologyManager,
|
||||
ghostdagDataStore,
|
||||
blockHeaderStore,
|
||||
config.K)
|
||||
dagParams.K)
|
||||
dagTraversalManager := dagtraversalmanager.New(
|
||||
dbManager,
|
||||
dagTopologyManager,
|
||||
@@ -168,20 +162,20 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
||||
reachabilityDataStore,
|
||||
ghostdagManager,
|
||||
consensusStateStore,
|
||||
config.GenesisHash)
|
||||
dagParams.GenesisHash)
|
||||
pastMedianTimeManager := f.pastMedianTimeConsructor(
|
||||
config.TimestampDeviationTolerance,
|
||||
dagParams.TimestampDeviationTolerance,
|
||||
dbManager,
|
||||
dagTraversalManager,
|
||||
blockHeaderStore,
|
||||
ghostdagDataStore,
|
||||
config.GenesisHash)
|
||||
transactionValidator := transactionvalidator.New(config.BlockCoinbaseMaturity,
|
||||
config.EnableNonNativeSubnetworks,
|
||||
config.MassPerTxByte,
|
||||
config.MassPerScriptPubKeyByte,
|
||||
config.MassPerSigOp,
|
||||
config.MaxCoinbasePayloadLength,
|
||||
dagParams.GenesisHash)
|
||||
transactionValidator := transactionvalidator.New(dagParams.BlockCoinbaseMaturity,
|
||||
dagParams.EnableNonNativeSubnetworks,
|
||||
dagParams.MassPerTxByte,
|
||||
dagParams.MassPerScriptPubKeyByte,
|
||||
dagParams.MassPerSigOp,
|
||||
dagParams.MaxCoinbasePayloadLength,
|
||||
dbManager,
|
||||
pastMedianTimeManager,
|
||||
ghostdagDataStore,
|
||||
@@ -194,29 +188,29 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
||||
daaBlocksStore,
|
||||
dagTopologyManager,
|
||||
dagTraversalManager,
|
||||
config.PowMax,
|
||||
config.DifficultyAdjustmentWindowSize,
|
||||
config.DisableDifficultyAdjustment,
|
||||
config.TargetTimePerBlock,
|
||||
config.GenesisHash)
|
||||
dagParams.PowMax,
|
||||
dagParams.DifficultyAdjustmentWindowSize,
|
||||
dagParams.DisableDifficultyAdjustment,
|
||||
dagParams.TargetTimePerBlock,
|
||||
dagParams.GenesisHash)
|
||||
coinbaseManager := coinbasemanager.New(
|
||||
dbManager,
|
||||
config.SubsidyReductionInterval,
|
||||
config.BaseSubsidy,
|
||||
config.CoinbasePayloadScriptPublicKeyMaxLength,
|
||||
dagParams.SubsidyReductionInterval,
|
||||
dagParams.BaseSubsidy,
|
||||
dagParams.CoinbasePayloadScriptPublicKeyMaxLength,
|
||||
ghostdagDataStore,
|
||||
acceptanceDataStore,
|
||||
daaBlocksStore)
|
||||
headerTipsManager := headersselectedtipmanager.New(dbManager, dagTopologyManager, dagTraversalManager,
|
||||
ghostdagManager, headersSelectedTipStore, headersSelectedChainStore)
|
||||
genesisHash := config.GenesisHash
|
||||
genesisHash := dagParams.GenesisHash
|
||||
finalityManager := finalitymanager.New(
|
||||
dbManager,
|
||||
dagTopologyManager,
|
||||
finalityStore,
|
||||
ghostdagDataStore,
|
||||
genesisHash,
|
||||
config.FinalityDepth())
|
||||
dagParams.FinalityDepth())
|
||||
mergeDepthManager := mergedepthmanager.New(
|
||||
dbManager,
|
||||
dagTopologyManager,
|
||||
@@ -224,15 +218,15 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
||||
finalityManager,
|
||||
ghostdagDataStore)
|
||||
blockValidator := blockvalidator.New(
|
||||
config.PowMax,
|
||||
config.SkipProofOfWork,
|
||||
dagParams.PowMax,
|
||||
dagParams.SkipProofOfWork,
|
||||
genesisHash,
|
||||
config.EnableNonNativeSubnetworks,
|
||||
config.MaxBlockSize,
|
||||
config.MergeSetSizeLimit,
|
||||
config.MaxBlockParents,
|
||||
config.TimestampDeviationTolerance,
|
||||
config.TargetTimePerBlock,
|
||||
dagParams.EnableNonNativeSubnetworks,
|
||||
dagParams.MaxBlockSize,
|
||||
dagParams.MergeSetSizeLimit,
|
||||
dagParams.MaxBlockParents,
|
||||
dagParams.TimestampDeviationTolerance,
|
||||
dagParams.TargetTimePerBlock,
|
||||
|
||||
dbManager,
|
||||
difficultyManager,
|
||||
@@ -255,10 +249,10 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
||||
)
|
||||
consensusStateManager, err := consensusstatemanager.New(
|
||||
dbManager,
|
||||
config.PruningDepth(),
|
||||
config.MaxMassAcceptedByBlock,
|
||||
config.MaxBlockParents,
|
||||
config.MergeSetSizeLimit,
|
||||
dagParams.PruningDepth(),
|
||||
dagParams.MaxMassAcceptedByBlock,
|
||||
dagParams.MaxBlockParents,
|
||||
dagParams.MergeSetSizeLimit,
|
||||
genesisHash,
|
||||
|
||||
ghostdagManager,
|
||||
@@ -305,11 +299,10 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
||||
blockHeaderStore,
|
||||
utxoDiffStore,
|
||||
daaBlocksStore,
|
||||
config.IsArchival,
|
||||
isArchivalNode,
|
||||
genesisHash,
|
||||
config.FinalityDepth(),
|
||||
config.PruningDepth(),
|
||||
config.EnableSanityCheckPruningUTXOSet)
|
||||
dagParams.FinalityDepth(),
|
||||
dagParams.PruningDepth())
|
||||
|
||||
syncManager := syncmanager.New(
|
||||
dbManager,
|
||||
@@ -343,7 +336,7 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
||||
|
||||
blockProcessor := blockprocessor.New(
|
||||
genesisHash,
|
||||
config.TargetTimePerBlock,
|
||||
dagParams.TargetTimePerBlock,
|
||||
dbManager,
|
||||
consensusStateManager,
|
||||
pruningManager,
|
||||
@@ -418,7 +411,7 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
||||
}
|
||||
|
||||
if !genesisInfo.Exists {
|
||||
_, err = c.ValidateAndInsertBlock(config.GenesisBlock)
|
||||
_, err = c.ValidateAndInsertBlock(dagParams.GenesisBlock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -432,7 +425,7 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = pruningManager.UpdatePruningPointIfRequired()
|
||||
err = pruningManager.UpdatePruningPointUTXOSetIfRequired()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -440,7 +433,7 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (f *factory) NewTestConsensus(config *Config, testName string) (
|
||||
func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, isArchivalNode bool, testName string) (
|
||||
tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) {
|
||||
datadir := f.dataDir
|
||||
if datadir == "" {
|
||||
@@ -462,7 +455,7 @@ func (f *factory) NewTestConsensus(config *Config, testName string) (
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
consensusAsInterface, err := f.NewConsensus(config, db)
|
||||
consensusAsInterface, err := f.NewConsensus(dagParams, db, isArchivalNode)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -472,7 +465,7 @@ func (f *factory) NewTestConsensus(config *Config, testName string) (
|
||||
testTransactionValidator := transactionvalidator.NewTestTransactionValidator(consensusAsImplementation.transactionValidator)
|
||||
|
||||
tstConsensus := &testConsensus{
|
||||
dagParams: &config.Params,
|
||||
dagParams: dagParams,
|
||||
consensus: consensusAsImplementation,
|
||||
database: db,
|
||||
testConsensusStateManager: testConsensusStateManager,
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
func TestNewConsensus(t *testing.T) {
|
||||
f := NewFactory()
|
||||
|
||||
config := &Config{Params: dagconfig.DevnetParams}
|
||||
dagParams := &dagconfig.DevnetParams
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "TestNewConsensus")
|
||||
if err != nil {
|
||||
@@ -23,7 +23,7 @@ func TestNewConsensus(t *testing.T) {
|
||||
t.Fatalf("error in NewLevelDB: %s", err)
|
||||
}
|
||||
|
||||
_, err = f.NewConsensus(config, db)
|
||||
_, err = f.NewConsensus(dagParams, db, false)
|
||||
if err != nil {
|
||||
t.Fatalf("error in NewConsensus: %+v", err)
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
package consensus_test
|
||||
package consensus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFinality(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
// Set finalityInterval to 50 blocks, so that test runs quickly
|
||||
consensusConfig.FinalityDuration = 50 * consensusConfig.TargetTimePerBlock
|
||||
params.FinalityDuration = 50 * params.TargetTimePerBlock
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
consensus, teardown, err := factory.NewTestConsensus(consensusConfig, "TestFinality")
|
||||
factory := NewFactory()
|
||||
consensus, teardown, err := factory.NewTestConsensus(params, false, "TestFinality")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
@@ -40,9 +40,9 @@ func TestFinality(t *testing.T) {
|
||||
}
|
||||
|
||||
// Build a chain of `finalityInterval - 1` blocks
|
||||
finalityInterval := consensusConfig.FinalityDepth()
|
||||
finalityInterval := params.FinalityDepth()
|
||||
var mainChainTip *externalapi.DomainBlock
|
||||
mainChainTipHash := consensusConfig.GenesisHash
|
||||
mainChainTipHash := params.GenesisHash
|
||||
|
||||
for i := uint64(0); i < finalityInterval-1; i++ {
|
||||
mainChainTip, err = buildAndInsertBlock([]*externalapi.DomainHash{mainChainTipHash})
|
||||
@@ -63,11 +63,11 @@ func TestFinality(t *testing.T) {
|
||||
|
||||
// Mine another chain of `finality-Interval - 2` blocks
|
||||
var sideChainTip *externalapi.DomainBlock
|
||||
sideChainTipHash := consensusConfig.GenesisHash
|
||||
sideChainTipHash := params.GenesisHash
|
||||
for i := uint64(0); i < finalityInterval-2; i++ {
|
||||
sideChainTip, err = buildAndInsertBlock([]*externalapi.DomainHash{sideChainTipHash})
|
||||
if err != nil {
|
||||
t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %+v", i, err)
|
||||
t.Fatalf("TestFinality: Failed to process sidechain Block #%d: %v", i, err)
|
||||
}
|
||||
sideChainTipHash = consensushashing.BlockHash(sideChainTip)
|
||||
|
||||
@@ -127,7 +127,7 @@ func TestFinality(t *testing.T) {
|
||||
t.Fatalf("TestFinality: Failed getting the virtual's finality point: %v", err)
|
||||
}
|
||||
|
||||
if virtualFinality.Equal(consensusConfig.GenesisHash) {
|
||||
if virtualFinality.Equal(params.GenesisHash) {
|
||||
t.Fatalf("virtual's finalityPoint is still genesis after adding finalityInterval + 1 blocks to the main chain")
|
||||
}
|
||||
|
||||
@@ -178,12 +178,12 @@ func TestFinality(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, params *dagconfig.Params) {
|
||||
// Set finalityInterval to 50 blocks, so that test runs quickly
|
||||
consensusConfig.FinalityDuration = 50 * consensusConfig.TargetTimePerBlock
|
||||
finalityInterval := int(consensusConfig.FinalityDepth())
|
||||
params.FinalityDuration = 50 * params.TargetTimePerBlock
|
||||
finalityInterval := int(params.FinalityDepth())
|
||||
|
||||
if int(consensusConfig.K) >= finalityInterval {
|
||||
if int(params.K) >= finalityInterval {
|
||||
t.Fatal("K must be smaller than finality duration for this test to run")
|
||||
}
|
||||
|
||||
@@ -235,20 +235,20 @@ func TestBoundedMergeDepth(t *testing.T) {
|
||||
return blockInfo.BlockStatus
|
||||
}
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
consensusBuild, teardownFunc1, err := factory.NewTestConsensus(consensusConfig, "TestBoundedMergeTestBuild")
|
||||
factory := NewFactory()
|
||||
consensusBuild, teardownFunc1, err := factory.NewTestConsensus(params, false, "TestBoundedMergeTestBuild")
|
||||
if err != nil {
|
||||
t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err)
|
||||
}
|
||||
|
||||
consensusReal, teardownFunc2, err := factory.NewTestConsensus(consensusConfig, "TestBoundedMergeTestReal")
|
||||
consensusReal, teardownFunc2, err := factory.NewTestConsensus(params, false, "TestBoundedMergeTestReal")
|
||||
if err != nil {
|
||||
t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardownFunc2(false)
|
||||
|
||||
// Create a block on top on genesis
|
||||
block1 := buildAndInsertBlock(consensusBuild, []*externalapi.DomainHash{consensusConfig.GenesisHash})
|
||||
block1 := buildAndInsertBlock(consensusBuild, []*externalapi.DomainHash{params.GenesisHash})
|
||||
|
||||
// Create a chain
|
||||
selectedChain := make([]*externalapi.DomainBlock, 0, finalityInterval+1)
|
||||
@@ -342,7 +342,7 @@ func TestBoundedMergeDepth(t *testing.T) {
|
||||
// Now let's make the kosherizing block red and try to merge again
|
||||
tip := consensushashing.BlockHash(selectedChain[len(selectedChain)-1])
|
||||
// we use k-1 because `kosherizingBlock` points at tip-2, so 2+k-1 = k+1 anticone.
|
||||
for i := 0; i < int(consensusConfig.K)-1; i++ {
|
||||
for i := 0; i < int(params.K)-1; i++ {
|
||||
block := buildAndInsertBlock(consensusReal, []*externalapi.DomainHash{tip})
|
||||
tip = consensushashing.BlockHash(block)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ type UTXODiff interface {
|
||||
ToRemove() UTXOCollection
|
||||
WithDiff(other UTXODiff) (UTXODiff, error)
|
||||
DiffFrom(other UTXODiff) (UTXODiff, error)
|
||||
Reversed() UTXODiff
|
||||
CloneMutable() MutableUTXODiff
|
||||
}
|
||||
|
||||
|
||||
@@ -6,19 +6,17 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
type PruningStore interface {
|
||||
Store
|
||||
StagePruningPoint(stagingArea *StagingArea, pruningPointBlockHash *externalapi.DomainHash)
|
||||
StagePreviousPruningPoint(stagingArea *StagingArea, oldPruningPointBlockHash *externalapi.DomainHash)
|
||||
StagePruningPointCandidate(stagingArea *StagingArea, candidate *externalapi.DomainHash)
|
||||
IsStaged(stagingArea *StagingArea) bool
|
||||
PruningPointCandidate(dbContext DBReader, stagingArea *StagingArea) (*externalapi.DomainHash, error)
|
||||
HasPruningPointCandidate(dbContext DBReader, stagingArea *StagingArea) (bool, error)
|
||||
PreviousPruningPoint(dbContext DBReader, stagingArea *StagingArea) (*externalapi.DomainHash, error)
|
||||
PruningPoint(dbContext DBReader, stagingArea *StagingArea) (*externalapi.DomainHash, error)
|
||||
HasPruningPoint(dbContext DBReader, stagingArea *StagingArea) (bool, error)
|
||||
|
||||
StageStartUpdatingPruningPointUTXOSet(stagingArea *StagingArea)
|
||||
HadStartedUpdatingPruningPointUTXOSet(dbContext DBWriter) (bool, error)
|
||||
FinishUpdatingPruningPointUTXOSet(dbContext DBWriter) error
|
||||
UpdatePruningPointUTXOSet(dbContext DBWriter, diff externalapi.UTXODiff) error
|
||||
UpdatePruningPointUTXOSet(dbContext DBWriter, utxoSetIterator externalapi.ReadOnlyUTXOSetIterator) error
|
||||
|
||||
ClearImportedPruningPointUTXOs(dbContext DBWriter) error
|
||||
AppendImportedPruningPointUTXOs(dbTx DBTransaction, outpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair) error
|
||||
@@ -28,5 +26,4 @@ type PruningStore interface {
|
||||
UpdateImportedPruningPointMultiset(dbTx DBTransaction, multiset Multiset) error
|
||||
CommitImportedPruningPointUTXOSet(dbContext DBWriter) error
|
||||
PruningPointUTXOs(dbContext DBReader, fromOutpoint *externalapi.DomainOutpoint, limit int) ([]*externalapi.OutpointAndUTXOEntryPair, error)
|
||||
PruningPointUTXOIterator(dbContext DBReader) (externalapi.ReadOnlyUTXOSetIterator, error)
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
|
||||
// ConsensusStateManager manages the node's consensus state
|
||||
type ConsensusStateManager interface {
|
||||
AddBlock(stagingArea *StagingArea, blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, externalapi.UTXODiff, *UTXODiffReversalData, error)
|
||||
AddBlock(stagingArea *StagingArea, blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, externalapi.UTXODiff, error)
|
||||
PopulateTransactionWithUTXOEntries(stagingArea *StagingArea, transaction *externalapi.DomainTransaction) error
|
||||
ImportPruningPoint(stagingArea *StagingArea, newPruningPoint *externalapi.DomainBlock) error
|
||||
RestorePastUTXOSetIterator(stagingArea *StagingArea, blockHash *externalapi.DomainHash) (externalapi.ReadOnlyUTXOSetIterator, error)
|
||||
CalculatePastUTXOAndAcceptanceData(stagingArea *StagingArea, blockHash *externalapi.DomainHash) (externalapi.UTXODiff, externalapi.AcceptanceData, Multiset, error)
|
||||
GetVirtualSelectedParentChainFromBlock(stagingArea *StagingArea, blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, error)
|
||||
RecoverUTXOIfRequired() error
|
||||
ReverseUTXODiffs(tipHash *externalapi.DomainHash, reversalData *UTXODiffReversalData) error
|
||||
}
|
||||
|
||||
@@ -8,6 +8,6 @@ type PruningManager interface {
|
||||
IsValidPruningPoint(stagingArea *StagingArea, blockHash *externalapi.DomainHash) (bool, error)
|
||||
ClearImportedPruningPointData() error
|
||||
AppendImportedPruningPointUTXOs(outpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair) error
|
||||
UpdatePruningPointIfRequired() error
|
||||
UpdatePruningPointUTXOSetIfRequired() error
|
||||
PruneAllBlocksBelow(stagingArea *StagingArea, pruningPointHash *externalapi.DomainHash) error
|
||||
}
|
||||
|
||||
@@ -11,5 +11,5 @@ type TestConsensusStateManager interface {
|
||||
AddUTXOToMultiset(multiset model.Multiset, entry externalapi.UTXOEntry,
|
||||
outpoint *externalapi.DomainOutpoint) error
|
||||
ResolveBlockStatus(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash,
|
||||
useSeparateStagingAreaPerBlock bool) (externalapi.BlockStatus, error)
|
||||
useSeparateStagingAreasPerBlock bool) (externalapi.BlockStatus, error)
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package model
|
||||
|
||||
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
|
||||
// UTXODiffReversalData is used by ConsensusStateManager to reverse the UTXODiffs during a re-org
|
||||
type UTXODiffReversalData struct {
|
||||
SelectedParentHash *externalapi.DomainHash
|
||||
SelectedParentUTXODiff externalapi.UTXODiff
|
||||
}
|
||||
@@ -1,21 +1,24 @@
|
||||
package blockbuilder_test
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestBuildBlockErrorCases(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
testConsensus, teardown, err := factory.NewTestConsensus(consensusConfig, "TestBlockBuilderErrorCases")
|
||||
testConsensus, teardown, err := factory.NewTestConsensus(
|
||||
params, false, "TestBlockBuilderErrorCases")
|
||||
if err != nil {
|
||||
t.Fatalf("Error initializing consensus for: %+v", err)
|
||||
}
|
||||
@@ -33,7 +36,7 @@ func TestBuildBlockErrorCases(t *testing.T) {
|
||||
"scriptPublicKey too long",
|
||||
&externalapi.DomainCoinbaseData{
|
||||
ScriptPublicKey: &externalapi.ScriptPublicKey{
|
||||
Script: make([]byte, consensusConfig.CoinbasePayloadScriptPublicKeyMaxLength+1),
|
||||
Script: make([]byte, params.CoinbasePayloadScriptPublicKeyMaxLength+1),
|
||||
Version: 0,
|
||||
},
|
||||
ExtraData: nil,
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/blockheader"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -119,11 +119,7 @@ func (bb *testBlockBuilder) buildBlockWithParents(stagingArea *model.StagingArea
|
||||
*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
||||
|
||||
if coinbaseData == nil {
|
||||
scriptPublicKeyScript, err := txscript.PayToScriptHashScript([]byte{txscript.OpTrue})
|
||||
if err != nil {
|
||||
panic(errors.Wrapf(err, "Couldn't parse opTrueScript. This should never happen"))
|
||||
}
|
||||
scriptPublicKey := &externalapi.ScriptPublicKey{Script: scriptPublicKeyScript, Version: constants.MaxScriptPublicKeyVersion}
|
||||
scriptPublicKey, _ := testutils.OpTrueScript()
|
||||
coinbaseData = &externalapi.DomainCoinbaseData{
|
||||
ScriptPublicKey: scriptPublicKey,
|
||||
ExtraData: []byte{},
|
||||
|
||||
@@ -90,7 +90,6 @@ func (bp *blockProcessor) validateAndInsertBlock(stagingArea *model.StagingArea,
|
||||
|
||||
var selectedParentChainChanges *externalapi.SelectedChainPath
|
||||
var virtualUTXODiff externalapi.UTXODiff
|
||||
var reversalData *model.UTXODiffReversalData
|
||||
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
|
||||
if !isHeaderOnlyBlock {
|
||||
// There's no need to update the consensus state manager when
|
||||
@@ -98,7 +97,7 @@ func (bp *blockProcessor) validateAndInsertBlock(stagingArea *model.StagingArea,
|
||||
// in consensusStateManager.ImportPruningPoint
|
||||
if !isPruningPoint {
|
||||
// Attempt to add the block to the virtual
|
||||
selectedParentChainChanges, virtualUTXODiff, reversalData, err = bp.consensusStateManager.AddBlock(stagingArea, blockHash)
|
||||
selectedParentChainChanges, virtualUTXODiff, err = bp.consensusStateManager.AddBlock(stagingArea, blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -125,14 +124,7 @@ func (bp *blockProcessor) validateAndInsertBlock(stagingArea *model.StagingArea,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if reversalData != nil {
|
||||
err = bp.consensusStateManager.ReverseUTXODiffs(blockHash, reversalData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = bp.pruningManager.UpdatePruningPointIfRequired()
|
||||
err = bp.pruningManager.UpdatePruningPointUTXOSetIfRequired()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -4,22 +4,25 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/blockheader"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestBlockStatus(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestBlockStatus")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestBlockStatus")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
@@ -36,7 +39,7 @@ func TestBlockStatus(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
tipHash := consensusConfig.GenesisHash
|
||||
tipHash := params.GenesisHash
|
||||
for i := 0; i < 2; i++ {
|
||||
tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil)
|
||||
if err != nil {
|
||||
@@ -53,7 +56,7 @@ func TestBlockStatus(t *testing.T) {
|
||||
|
||||
checkStatus(headerHash, externalapi.StatusHeaderOnly)
|
||||
|
||||
nonChainBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
nonChainBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -116,17 +119,17 @@ func TestValidateAndInsertErrors(t *testing.T) {
|
||||
// Each test is covering the error cases in a sub-function in "validateAndInsertBlock" function.
|
||||
// Currently, implemented only for some of the errors.
|
||||
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestBlockStatus")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestBlockStatus")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
tipHash, emptyCoinbase, tx1 := initData(consensusConfig)
|
||||
tipHash, emptyCoinbase, tx1 := initData(params)
|
||||
|
||||
// Tests all the error case on the function: "checkBlockStatus"(sub-function in function validateBlock)
|
||||
blockWithStatusInvalid, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash},
|
||||
blockWithStatusInvalid, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash},
|
||||
&emptyCoinbase, []*externalapi.DomainTransaction{tx1, tx1})
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
@@ -181,8 +184,8 @@ func TestValidateAndInsertErrors(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func initData(consensusConfig *consensus.Config) (*externalapi.DomainHash, externalapi.DomainCoinbaseData, *externalapi.DomainTransaction) {
|
||||
return consensusConfig.GenesisHash,
|
||||
func initData(params *dagconfig.Params) (*externalapi.DomainHash, externalapi.DomainCoinbaseData, *externalapi.DomainTransaction) {
|
||||
return params.GenesisHash,
|
||||
externalapi.DomainCoinbaseData{
|
||||
ScriptPublicKey: &externalapi.ScriptPublicKey{
|
||||
Script: nil,
|
||||
|
||||
@@ -42,27 +42,27 @@ func addBlock(tcSyncer, tcSyncee testapi.TestConsensus, parentHashes []*external
|
||||
}
|
||||
|
||||
func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
// This is done to reduce the pruning depth to 6 blocks
|
||||
finalityDepth := 3
|
||||
consensusConfig.FinalityDuration = time.Duration(finalityDepth) * consensusConfig.TargetTimePerBlock
|
||||
consensusConfig.K = 0
|
||||
params.FinalityDuration = time.Duration(finalityDepth) * params.TargetTimePerBlock
|
||||
params.K = 0
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
tcSyncer, teardownSyncer, err := factory.NewTestConsensus(consensusConfig, "TestValidateAndInsertPruningPointSyncer")
|
||||
tcSyncer, teardownSyncer, err := factory.NewTestConsensus(params, false, "TestValidateAndInsertPruningPointSyncer")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tcSyncer: %+v", err)
|
||||
}
|
||||
defer teardownSyncer(false)
|
||||
|
||||
tcSyncee, teardownSyncee, err := factory.NewTestConsensus(consensusConfig, "TestValidateAndInsertPruningPointSyncee")
|
||||
tcSyncee, teardownSyncee, err := factory.NewTestConsensus(params, false, "TestValidateAndInsertPruningPointSyncee")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tcSyncee: %+v", err)
|
||||
}
|
||||
defer teardownSyncee(false)
|
||||
|
||||
tipHash := consensusConfig.GenesisHash
|
||||
tipHash := params.GenesisHash
|
||||
for i := 0; i < finalityDepth-2; i++ {
|
||||
tipHash = addBlock(tcSyncer, tcSyncee, []*externalapi.DomainHash{tipHash}, t)
|
||||
}
|
||||
@@ -83,7 +83,7 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
|
||||
t.Fatalf("PruningPoint: %+v", err)
|
||||
}
|
||||
|
||||
if !pruningPoint.Equal(consensusConfig.GenesisHash) {
|
||||
if !pruningPoint.Equal(params.GenesisHash) {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -212,28 +212,28 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
|
||||
// IBD, while it already has a non-empty UTXO-Set originating from blocks mined on top of genesis - the resulting
|
||||
// UTXO set is correct
|
||||
func TestValidateAndInsertPruningPointWithSideBlocks(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
// This is done to reduce the pruning depth to 6 blocks
|
||||
finalityDepth := 3
|
||||
consensusConfig.FinalityDuration = time.Duration(finalityDepth) * consensusConfig.TargetTimePerBlock
|
||||
consensusConfig.K = 0
|
||||
params.FinalityDuration = time.Duration(finalityDepth) * params.TargetTimePerBlock
|
||||
params.K = 0
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
tcSyncer, teardownSyncer, err := factory.NewTestConsensus(consensusConfig, "TestValidateAndInsertPruningPointSyncer")
|
||||
tcSyncer, teardownSyncer, err := factory.NewTestConsensus(params, false, "TestValidateAndInsertPruningPointSyncer")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tcSyncer: %+v", err)
|
||||
}
|
||||
defer teardownSyncer(false)
|
||||
|
||||
tcSyncee, teardownSyncee, err := factory.NewTestConsensus(consensusConfig, "TestValidateAndInsertPruningPointSyncee")
|
||||
tcSyncee, teardownSyncee, err := factory.NewTestConsensus(params, false, "TestValidateAndInsertPruningPointSyncee")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tcSyncee: %+v", err)
|
||||
}
|
||||
defer teardownSyncee(false)
|
||||
|
||||
// Mine 2 block in the syncee on top of genesis
|
||||
side, _, err := tcSyncee.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, &externalapi.DomainCoinbaseData{ScriptPublicKey: &externalapi.ScriptPublicKey{}, ExtraData: []byte{1, 2}}, nil)
|
||||
side, _, err := tcSyncee.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, &externalapi.DomainCoinbaseData{ScriptPublicKey: &externalapi.ScriptPublicKey{}, ExtraData: []byte{1, 2}}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -242,7 +242,7 @@ func TestValidateAndInsertPruningPointWithSideBlocks(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tipHash := consensusConfig.GenesisHash
|
||||
tipHash := params.GenesisHash
|
||||
for i := 0; i < finalityDepth-2; i++ {
|
||||
tipHash = addBlock(tcSyncer, tcSyncee, []*externalapi.DomainHash{tipHash}, t)
|
||||
}
|
||||
@@ -261,7 +261,7 @@ func TestValidateAndInsertPruningPointWithSideBlocks(t *testing.T) {
|
||||
t.Fatalf("PruningPoint: %+v", err)
|
||||
}
|
||||
|
||||
if !pruningPoint.Equal(consensusConfig.GenesisHash) {
|
||||
if !pruningPoint.Equal(params.GenesisHash) {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -421,16 +421,16 @@ func makeFakeUTXOs() []*externalapi.OutpointAndUTXOEntryPair {
|
||||
}
|
||||
|
||||
func TestGetPruningPointUTXOs(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
// This is done to reduce the pruning depth to 8 blocks
|
||||
finalityDepth := 4
|
||||
consensusConfig.FinalityDuration = time.Duration(finalityDepth) * consensusConfig.TargetTimePerBlock
|
||||
consensusConfig.K = 0
|
||||
params.FinalityDuration = time.Duration(finalityDepth) * params.TargetTimePerBlock
|
||||
params.K = 0
|
||||
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
params.BlockCoinbaseMaturity = 0
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
testConsensus, teardown, err := factory.NewTestConsensus(consensusConfig, "TestGetPruningPointUTXOs")
|
||||
testConsensus, teardown, err := factory.NewTestConsensus(params, false, "TestGetPruningPointUTXOs")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up testConsensus: %+v", err)
|
||||
}
|
||||
@@ -518,7 +518,7 @@ func TestGetPruningPointUTXOs(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting the pruning point: %+v", err)
|
||||
}
|
||||
if !pruningPoint.Equal(consensusConfig.GenesisHash) {
|
||||
if !pruningPoint.Equal(params.GenesisHash) {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -580,18 +580,18 @@ func TestGetPruningPointUTXOs(t *testing.T) {
|
||||
}
|
||||
|
||||
func BenchmarkGetPruningPointUTXOs(b *testing.B) {
|
||||
consensusConfig := consensus.Config{Params: dagconfig.DevnetParams}
|
||||
params := dagconfig.DevnetParams
|
||||
|
||||
// This is done to reduce the pruning depth to 200 blocks
|
||||
finalityDepth := 100
|
||||
consensusConfig.FinalityDuration = time.Duration(finalityDepth) * consensusConfig.TargetTimePerBlock
|
||||
consensusConfig.K = 0
|
||||
params.FinalityDuration = time.Duration(finalityDepth) * params.TargetTimePerBlock
|
||||
params.K = 0
|
||||
|
||||
consensusConfig.SkipProofOfWork = true
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
params.SkipProofOfWork = true
|
||||
params.BlockCoinbaseMaturity = 0
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
testConsensus, teardown, err := factory.NewTestConsensus(&consensusConfig, "TestGetPruningPointUTXOs")
|
||||
testConsensus, teardown, err := factory.NewTestConsensus(¶ms, false, "TestGetPruningPointUTXOs")
|
||||
if err != nil {
|
||||
b.Fatalf("Error setting up testConsensus: %+v", err)
|
||||
}
|
||||
@@ -671,7 +671,7 @@ func BenchmarkGetPruningPointUTXOs(b *testing.B) {
|
||||
if err != nil {
|
||||
b.Fatalf("Error getting the pruning point: %+v", err)
|
||||
}
|
||||
if !pruningPoint.Equal(consensusConfig.GenesisHash) {
|
||||
if !pruningPoint.Equal(params.GenesisHash) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,25 +11,26 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestCheckBlockIsNotPruned(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
// This is done to reduce the pruning depth to 6 blocks
|
||||
consensusConfig.FinalityDuration = 2 * consensusConfig.TargetTimePerBlock
|
||||
consensusConfig.K = 0
|
||||
params.FinalityDuration = 2 * params.TargetTimePerBlock
|
||||
params.K = 0
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockIsNotPruned")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockIsNotPruned")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
// Add blocks until the pruning point changes
|
||||
tipHash := consensusConfig.GenesisHash
|
||||
tipHash := params.GenesisHash
|
||||
tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
@@ -51,7 +52,7 @@ func TestCheckBlockIsNotPruned(t *testing.T) {
|
||||
t.Fatalf("PruningPoint: %+v", err)
|
||||
}
|
||||
|
||||
if !pruningPoint.Equal(consensusConfig.GenesisHash) {
|
||||
if !pruningPoint.Equal(params.GenesisHash) {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -75,20 +76,20 @@ func TestCheckBlockIsNotPruned(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCheckParentBlockBodiesExist(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
// This is done to reduce the pruning depth to 6 blocks
|
||||
consensusConfig.FinalityDuration = 2 * consensusConfig.TargetTimePerBlock
|
||||
consensusConfig.K = 0
|
||||
params.FinalityDuration = 2 * params.TargetTimePerBlock
|
||||
params.K = 0
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckParentBlockBodiesExist")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckParentBlockBodiesExist")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
headerHash, _, err := tc.AddUTXOInvalidHeader([]*externalapi.DomainHash{consensusConfig.GenesisHash})
|
||||
headerHash, _, err := tc.AddUTXOInvalidHeader([]*externalapi.DomainHash{params.GenesisHash})
|
||||
if err != nil {
|
||||
t.Fatalf("AddUTXOInvalidHeader: %+v", err)
|
||||
}
|
||||
@@ -104,7 +105,7 @@ func TestCheckParentBlockBodiesExist(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add blocks until the pruning point changes
|
||||
tipHash := consensusConfig.GenesisHash
|
||||
tipHash := params.GenesisHash
|
||||
anticonePruningBlock, err := tc.BuildUTXOInvalidBlock([]*externalapi.DomainHash{tipHash})
|
||||
if err != nil {
|
||||
t.Fatalf("BuildUTXOInvalidBlock: %+v", err)
|
||||
@@ -130,7 +131,7 @@ func TestCheckParentBlockBodiesExist(t *testing.T) {
|
||||
t.Fatalf("PruningPoint: %+v", err)
|
||||
}
|
||||
|
||||
if !pruningPoint.Equal(consensusConfig.GenesisHash) {
|
||||
if !pruningPoint.Equal(params.GenesisHash) {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -145,20 +146,20 @@ func TestCheckParentBlockBodiesExist(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIsFinalizedTransaction(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
stagingArea := model.NewStagingArea()
|
||||
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
params.BlockCoinbaseMaturity = 0
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestIsFinalizedTransaction")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestIsFinalizedTransaction")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
// Build a small DAG
|
||||
outerParents := []*externalapi.DomainHash{consensusConfig.GenesisHash}
|
||||
outerParents := []*externalapi.DomainHash{params.GenesisHash}
|
||||
for i := 0; i < 5; i++ {
|
||||
var innerParents []*externalapi.DomainHash
|
||||
for i := 0; i < 4; i++ {
|
||||
|
||||
@@ -2,37 +2,39 @@ package blockvalidator_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/blockheader"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestChainedTransactions(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
params.BlockCoinbaseMaturity = 0
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestChainedTransactions")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestChainedTransactions")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
fundingBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
fundingBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -91,9 +93,9 @@ func TestChainedTransactions(t *testing.T) {
|
||||
// TestCheckBlockSanity tests the CheckBlockSanity function to ensure it works
|
||||
// as expected.
|
||||
func TestCheckBlockSanity(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockSanity")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockSanity")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
@@ -998,15 +1000,15 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{
|
||||
}
|
||||
|
||||
func TestCheckBlockHashMerkleRoot(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockHashMerkleRoot")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockHashMerkleRoot")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tc: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildBlockWithParents: %+v", err)
|
||||
}
|
||||
@@ -1028,16 +1030,16 @@ func TestCheckBlockHashMerkleRoot(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBlockSize(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestBlockSize")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestBlockSize")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tc: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
block, _, err := initBlockWithInvalidBlockSize(consensusConfig, tc)
|
||||
block, _, err := initBlockWithInvalidBlockSize(params, tc)
|
||||
if err != nil {
|
||||
t.Fatalf("Error BuildBlockWithParents : %+v", err)
|
||||
}
|
||||
@@ -1053,7 +1055,7 @@ func TestBlockSize(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func initBlockWithInvalidBlockSize(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
||||
func initBlockWithInvalidBlockSize(params *dagconfig.Params, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
||||
emptyCoinbase := externalapi.DomainCoinbaseData{
|
||||
ScriptPublicKey: &externalapi.ScriptPublicKey{
|
||||
Script: nil,
|
||||
@@ -1082,20 +1084,20 @@ func initBlockWithInvalidBlockSize(consensusConfig *consensus.Config, tc testapi
|
||||
Payload: []byte{0x01},
|
||||
}
|
||||
|
||||
return tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx})
|
||||
return tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx})
|
||||
}
|
||||
|
||||
func TestCheckBlockDuplicateTransactions(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockDuplicateTransactions")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockDuplicateTransactions")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tc: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
block, _, err := initBlockWithDuplicateTransaction(consensusConfig, tc)
|
||||
block, _, err := initBlockWithDuplicateTransaction(params, tc)
|
||||
if err != nil {
|
||||
t.Fatalf("Error BuildBlockWithParents : %+v", err)
|
||||
}
|
||||
@@ -1111,7 +1113,7 @@ func TestCheckBlockDuplicateTransactions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func initBlockWithDuplicateTransaction(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
||||
func initBlockWithDuplicateTransaction(params *dagconfig.Params, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
||||
emptyCoinbase := externalapi.DomainCoinbaseData{
|
||||
ScriptPublicKey: &externalapi.ScriptPublicKey{
|
||||
Script: nil,
|
||||
@@ -1139,20 +1141,20 @@ func initBlockWithDuplicateTransaction(consensusConfig *consensus.Config, tc tes
|
||||
SubnetworkID: subnetworks.SubnetworkIDNative,
|
||||
}
|
||||
|
||||
return tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx, tx})
|
||||
return tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx, tx})
|
||||
}
|
||||
|
||||
func TestCheckBlockContainsOnlyOneCoinbase(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockContainsOnlyOneCoinbase")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockContainsOnlyOneCoinbase")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tc: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
block, _, err := initBlockWithMoreThanOneCoinbase(consensusConfig, tc)
|
||||
block, _, err := initBlockWithMoreThanOneCoinbase(params, tc)
|
||||
if err != nil {
|
||||
t.Fatalf("Error BuildBlockWithParents : %+v", err)
|
||||
}
|
||||
@@ -1168,7 +1170,7 @@ func TestCheckBlockContainsOnlyOneCoinbase(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func initBlockWithMoreThanOneCoinbase(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
||||
func initBlockWithMoreThanOneCoinbase(params *dagconfig.Params, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
||||
emptyCoinbase := externalapi.DomainCoinbaseData{
|
||||
ScriptPublicKey: &externalapi.ScriptPublicKey{
|
||||
Script: nil,
|
||||
@@ -1196,20 +1198,20 @@ func initBlockWithMoreThanOneCoinbase(consensusConfig *consensus.Config, tc test
|
||||
SubnetworkID: subnetworks.SubnetworkIDCoinbase,
|
||||
}
|
||||
|
||||
return tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx})
|
||||
return tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx})
|
||||
}
|
||||
|
||||
func TestCheckBlockDoubleSpends(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockDoubleSpends")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockDoubleSpends")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tc: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
block, _, err := initBlockWithDoubleSpends(consensusConfig, tc)
|
||||
block, _, err := initBlockWithDoubleSpends(params, tc)
|
||||
if err != nil {
|
||||
t.Fatalf("Error BuildBlockWithParents : %+v", err)
|
||||
}
|
||||
@@ -1225,7 +1227,7 @@ func TestCheckBlockDoubleSpends(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func initBlockWithDoubleSpends(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
||||
func initBlockWithDoubleSpends(params *dagconfig.Params, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
||||
emptyCoinbase := externalapi.DomainCoinbaseData{
|
||||
ScriptPublicKey: &externalapi.ScriptPublicKey{
|
||||
Script: nil,
|
||||
@@ -1271,21 +1273,21 @@ func initBlockWithDoubleSpends(consensusConfig *consensus.Config, tc testapi.Tes
|
||||
SubnetworkID: subnetworks.SubnetworkIDNative,
|
||||
}
|
||||
|
||||
return tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash},
|
||||
return tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash},
|
||||
&emptyCoinbase, []*externalapi.DomainTransaction{tx, txSameOutpoint})
|
||||
}
|
||||
|
||||
func TestCheckFirstBlockTransactionIsCoinbase(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckFirstBlockTransactionIsCoinbase")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckFirstBlockTransactionIsCoinbase")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tc: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
block := initBlockWithFirstTransactionDifferentThanCoinbase(consensusConfig)
|
||||
block := initBlockWithFirstTransactionDifferentThanCoinbase(params)
|
||||
blockHash := consensushashing.BlockHash(block)
|
||||
stagingArea := model.NewStagingArea()
|
||||
tc.BlockStore().Stage(stagingArea, blockHash, block)
|
||||
@@ -1298,7 +1300,7 @@ func TestCheckFirstBlockTransactionIsCoinbase(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func initBlockWithFirstTransactionDifferentThanCoinbase(consensusConfig *consensus.Config) *externalapi.DomainBlock {
|
||||
func initBlockWithFirstTransactionDifferentThanCoinbase(params *dagconfig.Params) *externalapi.DomainBlock {
|
||||
prevOutTxID := &externalapi.DomainTransactionID{}
|
||||
prevOutPoint := externalapi.DomainOutpoint{TransactionID: *prevOutTxID, Index: 1}
|
||||
txInput := externalapi.DomainTransactionInput{
|
||||
@@ -1318,7 +1320,7 @@ func initBlockWithFirstTransactionDifferentThanCoinbase(consensusConfig *consens
|
||||
return &externalapi.DomainBlock{
|
||||
Header: blockheader.NewImmutableBlockHeader(
|
||||
constants.MaxBlockVersion,
|
||||
[]*externalapi.DomainHash{consensusConfig.GenesisHash},
|
||||
[]*externalapi.DomainHash{params.GenesisHash},
|
||||
merkle.CalculateHashMerkleRoot([]*externalapi.DomainTransaction{tx}),
|
||||
&externalapi.DomainHash{},
|
||||
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
|
||||
|
||||
@@ -12,12 +12,13 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
func TestValidateMedianTime(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestValidateMedianTime")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestValidateMedianTime")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
@@ -61,8 +62,8 @@ func TestValidateMedianTime(t *testing.T) {
|
||||
return pastMedianTime
|
||||
}
|
||||
|
||||
tip := consensusConfig.GenesisBlock
|
||||
tipHash := consensusConfig.GenesisHash
|
||||
tip := params.GenesisBlock
|
||||
tipHash := params.GenesisHash
|
||||
|
||||
blockTime := tip.Header.TimeInMilliseconds()
|
||||
|
||||
@@ -83,15 +84,15 @@ func TestValidateMedianTime(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCheckParentsIncest(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckParentsIncest")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckParentsIncest")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
a, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
a, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -101,7 +102,7 @@ func TestCheckParentsIncest(t *testing.T) {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
c, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
c, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -128,7 +129,7 @@ func TestCheckParentsIncest(t *testing.T) {
|
||||
indirectParentsRelationBlock := &externalapi.DomainBlock{
|
||||
Header: blockheader.NewImmutableBlockHeader(
|
||||
0,
|
||||
[]*externalapi.DomainHash{consensusConfig.GenesisHash, b},
|
||||
[]*externalapi.DomainHash{params.GenesisHash, b},
|
||||
&externalapi.DomainHash{},
|
||||
&externalapi.DomainHash{},
|
||||
&externalapi.DomainHash{},
|
||||
@@ -153,25 +154,25 @@ func TestCheckParentsIncest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCheckMergeSizeLimit(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.MergeSetSizeLimit = 2 * uint64(consensusConfig.K)
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
params.MergeSetSizeLimit = 2 * uint64(params.K)
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckParentsIncest")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckParentsIncest")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
chain1TipHash := consensusConfig.GenesisHash
|
||||
for i := uint64(0); i < consensusConfig.MergeSetSizeLimit+2; i++ {
|
||||
chain1TipHash := params.GenesisHash
|
||||
for i := uint64(0); i < params.MergeSetSizeLimit+2; i++ {
|
||||
chain1TipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{chain1TipHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
chain2TipHash := consensusConfig.GenesisHash
|
||||
for i := uint64(0); i < consensusConfig.MergeSetSizeLimit+1; i++ {
|
||||
chain2TipHash := params.GenesisHash
|
||||
for i := uint64(0); i < params.MergeSetSizeLimit+1; i++ {
|
||||
chain2TipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{chain2TipHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package blockvalidator_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
@@ -10,22 +8,24 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/blockheader"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"github.com/pkg/errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCheckParentsLimit(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckParentsLimit")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckParentsLimit")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
for i := model.KType(0); i < consensusConfig.MaxBlockParents+1; i++ {
|
||||
_, _, err = tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
for i := model.KType(0); i < params.MaxBlockParents+1; i++ {
|
||||
_, _, err = tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -44,16 +44,16 @@ func TestCheckParentsLimit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCheckBlockVersion(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockVersion")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockVersion")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildBlockWithParents: %+v", err)
|
||||
}
|
||||
@@ -77,23 +77,23 @@ func TestCheckBlockVersion(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCheckBlockTimestampInIsolation(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockTimestampInIsolation")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckBlockTimestampInIsolation")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildBlockWithParents: %+v", err)
|
||||
}
|
||||
|
||||
// Give 10 seconds slack to take care of the test duration
|
||||
timestamp := mstime.Now().UnixMilliseconds() +
|
||||
int64(consensusConfig.TimestampDeviationTolerance)*consensusConfig.TargetTimePerBlock.Milliseconds() + 10_000
|
||||
int64(params.TimestampDeviationTolerance)*params.TargetTimePerBlock.Milliseconds() + 10_000
|
||||
|
||||
block.Header = blockheader.NewImmutableBlockHeader(
|
||||
block.Header.Version(),
|
||||
|
||||
@@ -3,9 +3,9 @@ package blockvalidator
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/pow"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util/difficulty"
|
||||
|
||||
@@ -7,34 +7,36 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/pow"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/blockheader"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/mining"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/util/difficulty"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// TestPOW tests the validation of the block's POW.
|
||||
func TestPOW(t *testing.T) {
|
||||
// We set the flag "skip pow" to be false (second argument in the function) for not skipping the check of POW and validate its correctness.
|
||||
testutils.ForAllNets(t, false, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, false, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestPOW")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestPOW")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
// Builds and checks block with invalid POW.
|
||||
invalidBlockWrongPOW, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
invalidBlockWrongPOW, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -44,12 +46,12 @@ func TestPOW(t *testing.T) {
|
||||
t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrInvalidPoW, err)
|
||||
}
|
||||
|
||||
abovePowMaxBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
abovePowMaxBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
abovePowMaxTarget := big.NewInt(0).Add(big.NewInt(1), consensusConfig.PowMax)
|
||||
abovePowMaxTarget := big.NewInt(0).Add(big.NewInt(1), params.PowMax)
|
||||
abovePowMaxBlock.Header = blockheader.NewImmutableBlockHeader(
|
||||
abovePowMaxBlock.Header.Version(),
|
||||
abovePowMaxBlock.Header.ParentHashes(),
|
||||
@@ -66,7 +68,7 @@ func TestPOW(t *testing.T) {
|
||||
t.Fatalf("Unexpected error: %+v", err)
|
||||
}
|
||||
|
||||
negativeTargetBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
negativeTargetBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -88,7 +90,7 @@ func TestPOW(t *testing.T) {
|
||||
}
|
||||
|
||||
// test on a valid block.
|
||||
validBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
validBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -118,16 +120,16 @@ func solveBlockWithWrongPOW(block *externalapi.DomainBlock) *externalapi.DomainB
|
||||
}
|
||||
|
||||
func TestCheckParentHeadersExist(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckParentHeadersExist")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckParentHeadersExist")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
orphanBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
orphanBlock, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -157,7 +159,7 @@ func TestCheckParentHeadersExist(t *testing.T) {
|
||||
}
|
||||
|
||||
invalidBlock, _, err := tc.BuildBlockWithParents(
|
||||
[]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
[]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -181,7 +183,7 @@ func TestCheckParentHeadersExist(t *testing.T) {
|
||||
|
||||
invalidBlockHash := consensushashing.BlockHash(invalidBlock)
|
||||
|
||||
invalidBlockChild, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
invalidBlockChild, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -205,21 +207,21 @@ func TestCheckParentHeadersExist(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCheckPruningPointViolation(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
// This is done to reduce the pruning depth to 6 blocks
|
||||
consensusConfig.FinalityDuration = 2 * consensusConfig.TargetTimePerBlock
|
||||
consensusConfig.K = 0
|
||||
params.FinalityDuration = 2 * params.TargetTimePerBlock
|
||||
params.K = 0
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckPruningPointViolation")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestCheckPruningPointViolation")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
// Add blocks until the pruning point changes
|
||||
tipHash := consensusConfig.GenesisHash
|
||||
tipHash := params.GenesisHash
|
||||
for {
|
||||
tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil)
|
||||
if err != nil {
|
||||
@@ -231,12 +233,12 @@ func TestCheckPruningPointViolation(t *testing.T) {
|
||||
t.Fatalf("PruningPoint: %+v", err)
|
||||
}
|
||||
|
||||
if !pruningPoint.Equal(consensusConfig.GenesisHash) {
|
||||
if !pruningPoint.Equal(params.GenesisHash) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
_, _, err = tc.AddUTXOInvalidBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash})
|
||||
_, _, err = tc.AddUTXOInvalidBlock([]*externalapi.DomainHash{params.GenesisHash})
|
||||
if !errors.Is(err, ruleerrors.ErrPruningPointViolation) {
|
||||
t.Fatalf("Unexpected error: %+v", err)
|
||||
}
|
||||
@@ -249,7 +251,7 @@ func TestCheckPruningPointViolation(t *testing.T) {
|
||||
// "calculated" by the mocDifficultyManager, where mocDifficultyManager is special implementation
|
||||
// of the type DifficultyManager for this test (defined below).
|
||||
func TestValidateDifficulty(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
mocDifficulty := &mocDifficultyManager{}
|
||||
factory.SetTestDifficultyManager(func(_ model.DBReader, _ model.GHOSTDAGManager, _ model.GHOSTDAGDataStore,
|
||||
@@ -260,10 +262,10 @@ func TestValidateDifficulty(t *testing.T) {
|
||||
mocDifficulty.daaBlocksStore = daaBlocksStore
|
||||
return mocDifficulty
|
||||
})
|
||||
genesisDifficulty := consensusConfig.GenesisBlock.Header.Bits()
|
||||
genesisDifficulty := params.GenesisBlock.Header.Bits()
|
||||
mocDifficulty.testDifficulty = genesisDifficulty
|
||||
mocDifficulty.testGenesisBits = genesisDifficulty
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestValidateDifficulty")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestValidateDifficulty")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
@@ -275,7 +277,7 @@ func TestValidateDifficulty(t *testing.T) {
|
||||
Version: 0,
|
||||
},
|
||||
}
|
||||
block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, &emptyCoinbase, nil)
|
||||
block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, &emptyCoinbase, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("TestValidateDifficulty: Failed build block with parents: %v.", err)
|
||||
}
|
||||
|
||||
@@ -9,19 +9,16 @@ import (
|
||||
// AddBlock submits the given block to be added to the
|
||||
// current virtual. This process may result in a new virtual block
|
||||
// getting created
|
||||
func (csm *consensusStateManager) AddBlock(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) (
|
||||
*externalapi.SelectedChainPath, externalapi.UTXODiff, *model.UTXODiffReversalData, error) {
|
||||
|
||||
func (csm *consensusStateManager) AddBlock(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) (*externalapi.SelectedChainPath, externalapi.UTXODiff, error) {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "csm.AddBlock")
|
||||
defer onEnd()
|
||||
|
||||
log.Debugf("Resolving whether the block %s is the next virtual selected parent", blockHash)
|
||||
isCandidateToBeNextVirtualSelectedParent, err := csm.isCandidateToBeNextVirtualSelectedParent(stagingArea, blockHash)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var reversalData *model.UTXODiffReversalData
|
||||
if isCandidateToBeNextVirtualSelectedParent {
|
||||
// It's important to check for finality violation before resolving the block status, because the status of
|
||||
// blocks with a selected chain that doesn't contain the pruning point cannot be resolved because they will
|
||||
@@ -30,7 +27,7 @@ func (csm *consensusStateManager) AddBlock(stagingArea *model.StagingArea, block
|
||||
"finality", blockHash)
|
||||
isViolatingFinality, shouldNotify, err := csm.isViolatingFinality(stagingArea, blockHash)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if shouldNotify {
|
||||
@@ -40,10 +37,9 @@ func (csm *consensusStateManager) AddBlock(stagingArea *model.StagingArea, block
|
||||
|
||||
if !isViolatingFinality {
|
||||
log.Debugf("Block %s doesn't violate finality. Resolving its block status", blockHash)
|
||||
var blockStatus externalapi.BlockStatus
|
||||
blockStatus, reversalData, err = csm.resolveBlockStatus(stagingArea, blockHash, true)
|
||||
blockStatus, err := csm.resolveBlockStatus(stagingArea, blockHash, true)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
log.Debugf("Block %s resolved to status `%s`", blockHash, blockStatus)
|
||||
@@ -56,17 +52,17 @@ func (csm *consensusStateManager) AddBlock(stagingArea *model.StagingArea, block
|
||||
log.Debugf("Adding block %s to the DAG tips", blockHash)
|
||||
newTips, err := csm.addTip(stagingArea, blockHash)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
log.Debugf("After adding %s, the amount of new tips are %d", blockHash, len(newTips))
|
||||
|
||||
log.Debugf("Updating the virtual with the new tips")
|
||||
selectedParentChainChanges, virtualUTXODiff, err := csm.updateVirtual(stagingArea, blockHash, newTips)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return selectedParentChainChanges, virtualUTXODiff, reversalData, nil
|
||||
return selectedParentChainChanges, virtualUTXODiff, nil
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) isCandidateToBeNextVirtualSelectedParent(
|
||||
|
||||
@@ -10,19 +10,20 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
func TestVirtualDiff(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestVirtualDiff")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestVirtualDiff")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tc: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
// Add block A over the genesis
|
||||
blockAHash, blockInsertionResult, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
blockAHash, blockInsertionResult, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error adding block A: %+v", err)
|
||||
}
|
||||
|
||||
@@ -39,27 +39,15 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(stagingArea
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
log.Debugf("Restored the past UTXO of block %s with selectedParent %s. "+
|
||||
"Diff toAdd length: %d, toRemove length: %d", blockHash, blockGHOSTDAGData.SelectedParent(),
|
||||
selectedParentPastUTXO.ToAdd().Len(), selectedParentPastUTXO.ToRemove().Len())
|
||||
|
||||
return csm.calculatePastUTXOAndAcceptanceDataWithSelectedParentUTXO(stagingArea, blockHash, selectedParentPastUTXO)
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) calculatePastUTXOAndAcceptanceDataWithSelectedParentUTXO(stagingArea *model.StagingArea,
|
||||
blockHash *externalapi.DomainHash, selectedParentPastUTXO externalapi.UTXODiff) (
|
||||
externalapi.UTXODiff, externalapi.AcceptanceData, model.Multiset, error) {
|
||||
|
||||
blockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, stagingArea, blockHash)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
daaScore, err := csm.daaBlocksStore.DAAScore(csm.databaseContext, stagingArea, blockHash)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
log.Debugf("Restored the past UTXO of block %s with selectedParent %s. "+
|
||||
"Diff toAdd length: %d, toRemove length: %d", blockHash, blockGHOSTDAGData.SelectedParent(),
|
||||
selectedParentPastUTXO.ToAdd().Len(), selectedParentPastUTXO.ToRemove().Len())
|
||||
|
||||
log.Debugf("Applying blue blocks to the selected parent past UTXO of block %s", blockHash)
|
||||
acceptanceData, utxoDiff, err := csm.applyMergeSetBlocks(
|
||||
stagingArea, blockHash, selectedParentPastUTXO, blockGHOSTDAGData, daaScore)
|
||||
@@ -78,7 +66,7 @@ func (csm *consensusStateManager) calculatePastUTXOAndAcceptanceDataWithSelected
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) restorePastUTXO(
|
||||
stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) (externalapi.UTXODiff, error) {
|
||||
stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) (externalapi.MutableUTXODiff, error) {
|
||||
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "restorePastUTXO")
|
||||
defer onEnd()
|
||||
@@ -132,11 +120,11 @@ func (csm *consensusStateManager) restorePastUTXO(
|
||||
}
|
||||
log.Tracef("The accumulated diff for block %s is: %s", blockHash, accumulatedDiff)
|
||||
|
||||
return accumulatedDiff.ToImmutable(), nil
|
||||
return accumulatedDiff, nil
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) applyMergeSetBlocks(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash,
|
||||
selectedParentPastUTXODiff externalapi.UTXODiff, ghostdagData *model.BlockGHOSTDAGData, daaScore uint64) (
|
||||
selectedParentPastUTXODiff externalapi.MutableUTXODiff, ghostdagData *model.BlockGHOSTDAGData, daaScore uint64) (
|
||||
externalapi.AcceptanceData, externalapi.MutableUTXODiff, error) {
|
||||
|
||||
log.Debugf("applyMergeSetBlocks start for block %s", blockHash)
|
||||
@@ -156,7 +144,7 @@ func (csm *consensusStateManager) applyMergeSetBlocks(stagingArea *model.Staging
|
||||
log.Tracef("The past median time for block %s is: %d", blockHash, selectedParentMedianTime)
|
||||
|
||||
multiblockAcceptanceData := make(externalapi.AcceptanceData, len(mergeSetBlocks))
|
||||
accumulatedUTXODiff := selectedParentPastUTXODiff.CloneMutable()
|
||||
accumulatedUTXODiff := selectedParentPastUTXODiff
|
||||
accumulatedMass := uint64(0)
|
||||
|
||||
for i, mergeSetBlock := range mergeSetBlocks {
|
||||
@@ -289,13 +277,12 @@ func (csm *consensusStateManager) checkTransactionMass(
|
||||
}
|
||||
|
||||
// RestorePastUTXOSetIterator restores the given block's UTXOSet iterator, and returns it as a externalapi.ReadOnlyUTXOSetIterator
|
||||
func (csm *consensusStateManager) RestorePastUTXOSetIterator(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) (
|
||||
externalapi.ReadOnlyUTXOSetIterator, error) {
|
||||
func (csm *consensusStateManager) RestorePastUTXOSetIterator(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) (externalapi.ReadOnlyUTXOSetIterator, error) {
|
||||
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "RestorePastUTXOSetIterator")
|
||||
defer onEnd()
|
||||
|
||||
blockStatus, _, err := csm.resolveBlockStatus(stagingArea, blockHash, true)
|
||||
blockStatus, err := csm.resolveBlockStatus(stagingArea, blockHash, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -319,5 +306,5 @@ func (csm *consensusStateManager) RestorePastUTXOSetIterator(stagingArea *model.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return utxo.IteratorWithDiff(virtualUTXOSetIterator, blockDiff)
|
||||
return utxo.IteratorWithDiff(virtualUTXOSetIterator, blockDiff.ToImmutable())
|
||||
}
|
||||
|
||||
@@ -3,21 +3,25 @@ package consensusstatemanager_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/multiset"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
func TestUTXOCommitment(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
params.BlockCoinbaseMaturity = 0
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
consensus, teardown, err := factory.NewTestConsensus(consensusConfig, "TestUTXOCommitment")
|
||||
consensus, teardown, err := factory.NewTestConsensus(params, false, "TestUTXOCommitment")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
@@ -27,7 +31,7 @@ func TestUTXOCommitment(t *testing.T) {
|
||||
// G <- A <- B <- C <- E
|
||||
// <- D <-
|
||||
// Where block D has a non-coinbase transaction
|
||||
genesisHash := consensusConfig.GenesisHash
|
||||
genesisHash := params.GenesisHash
|
||||
|
||||
// Block A:
|
||||
blockAHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{genesisHash}, nil, nil)
|
||||
@@ -111,19 +115,19 @@ func checkBlockUTXOCommitment(t *testing.T, consensus testapi.TestConsensus, blo
|
||||
}
|
||||
|
||||
func TestPastUTXOMultiset(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
stagingArea := model.NewStagingArea()
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
consensus, teardown, err := factory.NewTestConsensus(consensusConfig, "TestUTXOCommitment")
|
||||
consensus, teardown, err := factory.NewTestConsensus(params, false, "TestUTXOCommitment")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
// Build a short chain
|
||||
currentHash := consensusConfig.GenesisHash
|
||||
currentHash := params.GenesisHash
|
||||
for i := 0; i < 3; i++ {
|
||||
currentHash, _, err = consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -7,19 +7,20 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
func TestCalculateChainPath(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
consensus, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCalculateChainPath")
|
||||
consensus, teardown, err := factory.NewTestConsensus(params, false, "TestCalculateChainPath")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
// Add block A over the genesis
|
||||
blockAHash, blockAInsertionResult, err := consensus.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
blockAHash, blockAInsertionResult, err := consensus.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error adding block A: %+v", err)
|
||||
}
|
||||
@@ -41,7 +42,7 @@ func TestCalculateChainPath(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add block B over the genesis
|
||||
blockBHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
blockBHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error adding block B: %+v", err)
|
||||
}
|
||||
@@ -92,7 +93,7 @@ func TestCalculateChainPath(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add block D over the genesis
|
||||
_, blockDInsertionResult, err := consensus.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
_, blockDInsertionResult, err := consensus.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error adding block D: %+v", err)
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ package consensusstatemanager
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
|
||||
"github.com/kaspanet/kaspad/util/staging"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
@@ -15,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
func (csm *consensusStateManager) resolveBlockStatus(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash,
|
||||
useSeparateStagingAreaPerBlock bool) (externalapi.BlockStatus, *model.UTXODiffReversalData, error) {
|
||||
useSeparateStagingAreasPerBlock bool) (externalapi.BlockStatus, error) {
|
||||
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, fmt.Sprintf("resolveBlockStatus for %s", blockHash))
|
||||
defer onEnd()
|
||||
@@ -24,7 +22,7 @@ func (csm *consensusStateManager) resolveBlockStatus(stagingArea *model.StagingA
|
||||
"parent chain of %s that have no yet resolved their status", blockHash)
|
||||
unverifiedBlocks, err := csm.getUnverifiedChainBlocks(stagingArea, blockHash)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return 0, err
|
||||
}
|
||||
log.Debugf("Got %d unverified blocks in the selected parent "+
|
||||
"chain of %s: %s", len(unverifiedBlocks), blockHash, unverifiedBlocks)
|
||||
@@ -36,33 +34,26 @@ func (csm *consensusStateManager) resolveBlockStatus(stagingArea *model.StagingA
|
||||
"This means that the block already has a UTXO-verified status.", blockHash)
|
||||
status, err := csm.blockStatusStore.Get(csm.databaseContext, stagingArea, blockHash)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return 0, err
|
||||
}
|
||||
log.Debugf("Block %s's status resolved to: %s", blockHash, status)
|
||||
return status, nil, nil
|
||||
return status, nil
|
||||
}
|
||||
|
||||
log.Debugf("Finding the status of the selected parent of %s", blockHash)
|
||||
selectedParentHash, selectedParentStatus, selectedParentUTXOSet, err := csm.selectedParentInfo(stagingArea, unverifiedBlocks)
|
||||
selectedParentStatus, err := csm.findSelectedParentStatus(stagingArea, unverifiedBlocks)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return 0, err
|
||||
}
|
||||
log.Debugf("The status of the selected parent of %s is: %s", blockHash, selectedParentStatus)
|
||||
|
||||
log.Debugf("Resolving the unverified blocks' status in reverse order (past to present)")
|
||||
var blockStatus externalapi.BlockStatus
|
||||
|
||||
previousBlockHash := selectedParentHash
|
||||
previousBlockUTXOSet := selectedParentUTXOSet
|
||||
var oneBeforeLastResolvedBlockUTXOSet externalapi.UTXODiff
|
||||
var oneBeforeLastResolvedBlockHash *externalapi.DomainHash
|
||||
|
||||
for i := len(unverifiedBlocks) - 1; i >= 0; i-- {
|
||||
unverifiedBlockHash := unverifiedBlocks[i]
|
||||
|
||||
stagingAreaForCurrentBlock := stagingArea
|
||||
isResolveTip := i == 0
|
||||
useSeparateStagingArea := useSeparateStagingAreaPerBlock && !isResolveTip
|
||||
useSeparateStagingArea := useSeparateStagingAreasPerBlock && (i != 0)
|
||||
if useSeparateStagingArea {
|
||||
stagingAreaForCurrentBlock = model.NewStagingArea()
|
||||
}
|
||||
@@ -70,13 +61,9 @@ func (csm *consensusStateManager) resolveBlockStatus(stagingArea *model.StagingA
|
||||
if selectedParentStatus == externalapi.StatusDisqualifiedFromChain {
|
||||
blockStatus = externalapi.StatusDisqualifiedFromChain
|
||||
} else {
|
||||
oneBeforeLastResolvedBlockUTXOSet = previousBlockUTXOSet
|
||||
oneBeforeLastResolvedBlockHash = previousBlockHash
|
||||
|
||||
blockStatus, previousBlockUTXOSet, err = csm.resolveSingleBlockStatus(
|
||||
stagingAreaForCurrentBlock, unverifiedBlockHash, previousBlockHash, previousBlockUTXOSet, isResolveTip)
|
||||
blockStatus, err = csm.resolveSingleBlockStatus(stagingAreaForCurrentBlock, unverifiedBlockHash)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,39 +75,17 @@ func (csm *consensusStateManager) resolveBlockStatus(stagingArea *model.StagingA
|
||||
if useSeparateStagingArea {
|
||||
err := staging.CommitAllChanges(csm.databaseContext, stagingAreaForCurrentBlock)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
previousBlockHash = unverifiedBlockHash
|
||||
}
|
||||
|
||||
var reversalData *model.UTXODiffReversalData
|
||||
if blockStatus == externalapi.StatusUTXOValid && len(unverifiedBlocks) > 1 {
|
||||
log.Debugf("Preparing data for reversing the UTXODiff")
|
||||
// During resolveSingleBlockStatus, all unverifiedBlocks (excluding the tip) were assigned their selectedParent
|
||||
// as their UTXODiffChild.
|
||||
// Now that the whole chain has been resolved - we can reverse the UTXODiffs, to create shorter UTXODiffChild paths.
|
||||
// However, we can't do this right now, because the tip of the chain is not yet committed, so we prepare the
|
||||
// needed data (tip's selectedParent and selectedParent's UTXODiff)
|
||||
selectedParentUTXODiff, err := previousBlockUTXOSet.DiffFrom(oneBeforeLastResolvedBlockUTXOSet)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
reversalData = &model.UTXODiffReversalData{
|
||||
SelectedParentHash: oneBeforeLastResolvedBlockHash,
|
||||
SelectedParentUTXODiff: selectedParentUTXODiff,
|
||||
}
|
||||
}
|
||||
|
||||
return blockStatus, reversalData, nil
|
||||
return blockStatus, nil
|
||||
}
|
||||
|
||||
// selectedParentInfo returns the hash and status of the selectedParent of the last block in the unverifiedBlocks
|
||||
// chain, in addition, if the status is UTXOValid, it return it's pastUTXOSet
|
||||
func (csm *consensusStateManager) selectedParentInfo(
|
||||
stagingArea *model.StagingArea, unverifiedBlocks []*externalapi.DomainHash) (
|
||||
*externalapi.DomainHash, externalapi.BlockStatus, externalapi.UTXODiff, error) {
|
||||
// findSelectedParentStatus returns the status of the selectedParent of the last block in the unverifiedBlocks chain
|
||||
func (csm *consensusStateManager) findSelectedParentStatus(
|
||||
stagingArea *model.StagingArea, unverifiedBlocks []*externalapi.DomainHash) (externalapi.BlockStatus, error) {
|
||||
|
||||
log.Debugf("findSelectedParentStatus start")
|
||||
defer log.Debugf("findSelectedParentStatus end")
|
||||
@@ -129,26 +94,13 @@ func (csm *consensusStateManager) selectedParentInfo(
|
||||
if lastUnverifiedBlock.Equal(csm.genesisHash) {
|
||||
log.Debugf("the most recent unverified block is the genesis block, "+
|
||||
"which by definition has status: %s", externalapi.StatusUTXOValid)
|
||||
return lastUnverifiedBlock, externalapi.StatusUTXOValid, utxo.NewUTXODiff(), nil
|
||||
return externalapi.StatusUTXOValid, nil
|
||||
}
|
||||
lastUnverifiedBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, stagingArea, lastUnverifiedBlock)
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
return 0, err
|
||||
}
|
||||
selectedParent := lastUnverifiedBlockGHOSTDAGData.SelectedParent()
|
||||
selectedParentStatus, err := csm.blockStatusStore.Get(csm.databaseContext, stagingArea, selectedParent)
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
if selectedParentStatus != externalapi.StatusUTXOValid {
|
||||
return selectedParent, selectedParentStatus, nil, nil
|
||||
}
|
||||
|
||||
selectedParentUTXOSet, err := csm.restorePastUTXO(stagingArea, selectedParent)
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
return selectedParent, selectedParentStatus, selectedParentUTXOSet, nil
|
||||
return csm.blockStatusStore.Get(csm.databaseContext, stagingArea, lastUnverifiedBlockGHOSTDAGData.SelectedParent())
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) getUnverifiedChainBlocks(stagingArea *model.StagingArea,
|
||||
@@ -190,17 +142,15 @@ func (csm *consensusStateManager) getUnverifiedChainBlocks(stagingArea *model.St
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) resolveSingleBlockStatus(stagingArea *model.StagingArea,
|
||||
blockHash, selectedParentHash *externalapi.DomainHash, selectedParentPastUTXOSet externalapi.UTXODiff, isResolveTip bool) (
|
||||
externalapi.BlockStatus, externalapi.UTXODiff, error) {
|
||||
blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) {
|
||||
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, fmt.Sprintf("resolveSingleBlockStatus for %s", blockHash))
|
||||
defer onEnd()
|
||||
|
||||
log.Tracef("Calculating pastUTXO and acceptance data and multiset for block %s", blockHash)
|
||||
pastUTXOSet, acceptanceData, multiset, err := csm.calculatePastUTXOAndAcceptanceDataWithSelectedParentUTXO(
|
||||
stagingArea, blockHash, selectedParentPastUTXOSet)
|
||||
pastUTXODiff, acceptanceData, multiset, err := csm.CalculatePastUTXOAndAcceptanceData(stagingArea, blockHash)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
log.Tracef("Staging the calculated acceptance data of block %s", blockHash)
|
||||
@@ -208,17 +158,17 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(stagingArea *model.St
|
||||
|
||||
block, err := csm.blockStore.Block(csm.databaseContext, stagingArea, blockHash)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
log.Tracef("verifying the UTXO of block %s", blockHash)
|
||||
err = csm.verifyUTXO(stagingArea, block, blockHash, pastUTXOSet, acceptanceData, multiset)
|
||||
err = csm.verifyUTXO(stagingArea, block, blockHash, pastUTXODiff, acceptanceData, multiset)
|
||||
if err != nil {
|
||||
if errors.As(err, &ruleerrors.RuleError{}) {
|
||||
log.Debugf("UTXO verification for block %s failed: %s", blockHash, err)
|
||||
return externalapi.StatusDisqualifiedFromChain, nil, nil
|
||||
return externalapi.StatusDisqualifiedFromChain, nil
|
||||
}
|
||||
return 0, nil, err
|
||||
return 0, err
|
||||
}
|
||||
log.Debugf("UTXO verification for block %s passed", blockHash)
|
||||
|
||||
@@ -227,62 +177,45 @@ func (csm *consensusStateManager) resolveSingleBlockStatus(stagingArea *model.St
|
||||
|
||||
if csm.genesisHash.Equal(blockHash) {
|
||||
log.Tracef("Staging the utxoDiff of genesis")
|
||||
csm.stageDiff(stagingArea, blockHash, pastUTXOSet, nil)
|
||||
return externalapi.StatusUTXOValid, nil, nil
|
||||
csm.stageDiff(stagingArea, blockHash, pastUTXODiff, nil)
|
||||
return externalapi.StatusUTXOValid, nil
|
||||
}
|
||||
|
||||
oldSelectedTip, err := csm.selectedTip(stagingArea)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if isResolveTip {
|
||||
oldSelectedTipUTXOSet, err := csm.restorePastUTXO(stagingArea, oldSelectedTip)
|
||||
isNewSelectedTip, err := csm.isNewSelectedTip(stagingArea, blockHash, oldSelectedTip)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
oldSelectedTipUTXOSet, err := csm.restorePastUTXO(stagingArea, oldSelectedTip)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if isNewSelectedTip {
|
||||
log.Debugf("Block %s is the new SelectedTip, therefore setting it as old selectedTip's diffChild", blockHash)
|
||||
oldSelectedTipUTXOSet, err := pastUTXODiff.DiffFrom(oldSelectedTipUTXOSet.ToImmutable())
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
isNewSelectedTip, err := csm.isNewSelectedTip(stagingArea, blockHash, oldSelectedTip)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return 0, err
|
||||
}
|
||||
csm.stageDiff(stagingArea, oldSelectedTip, oldSelectedTipUTXOSet, blockHash)
|
||||
|
||||
if isNewSelectedTip {
|
||||
log.Debugf("Block %s is the new selected tip, therefore setting it as old selected tip's diffChild", blockHash)
|
||||
|
||||
updatedOldSelectedTipUTXOSet, err := pastUTXOSet.DiffFrom(oldSelectedTipUTXOSet)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
log.Debugf("Setting the old selected tip's (%s) diffChild to be the new selected tip (%s)",
|
||||
oldSelectedTip, blockHash)
|
||||
csm.stageDiff(stagingArea, oldSelectedTip, updatedOldSelectedTipUTXOSet, blockHash)
|
||||
|
||||
log.Tracef("Staging the utxoDiff of block %s, with virtual as diffChild", blockHash)
|
||||
csm.stageDiff(stagingArea, blockHash, pastUTXOSet, nil)
|
||||
} else {
|
||||
log.Debugf("Block %s is the tip of currently resolved chain, but not the new selected tip,"+
|
||||
"therefore setting it's utxoDiffChild to be the current selectedTip %s", blockHash, oldSelectedTip)
|
||||
utxoDiff, err := oldSelectedTipUTXOSet.DiffFrom(pastUTXOSet)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
csm.stageDiff(stagingArea, blockHash, utxoDiff, oldSelectedTip)
|
||||
}
|
||||
log.Tracef("Staging the utxoDiff of block %s", blockHash)
|
||||
csm.stageDiff(stagingArea, blockHash, pastUTXODiff, nil)
|
||||
} else {
|
||||
// If the block is not the tip of the currently resolved chain, we set it's diffChild to be the selectedParent,
|
||||
// this is a temporary measure to ensure there's a restore path to all blocks at all times.
|
||||
// Later down the process, the diff will be reversed in reverseUTXODiffs.
|
||||
log.Debugf("Block %s is not the new selected tip, and is not the tip of the currently verified chain, "+
|
||||
"therefore temporarily setting selectedParent as it's diffChild", blockHash)
|
||||
utxoDiff, err := selectedParentPastUTXOSet.DiffFrom(pastUTXOSet)
|
||||
log.Debugf("Block %s is not the new SelectedTip, therefore setting old selectedTip as it's diffChild", blockHash)
|
||||
pastUTXODiff, err = oldSelectedTipUTXOSet.DiffFrom(pastUTXODiff)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
csm.stageDiff(stagingArea, blockHash, utxoDiff, selectedParentHash)
|
||||
log.Tracef("Staging the utxoDiff of block %s", blockHash)
|
||||
csm.stageDiff(stagingArea, blockHash, pastUTXODiff, oldSelectedTip)
|
||||
}
|
||||
|
||||
return externalapi.StatusUTXOValid, pastUTXOSet, nil
|
||||
return externalapi.StatusUTXOValid, nil
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) isNewSelectedTip(stagingArea *model.StagingArea,
|
||||
|
||||
@@ -16,24 +16,25 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
func TestDoubleSpends(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
stagingArea := model.NewStagingArea()
|
||||
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
params.BlockCoinbaseMaturity = 0
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
consensus, teardown, err := factory.NewTestConsensus(consensusConfig, "TestUTXOCommitment")
|
||||
consensus, teardown, err := factory.NewTestConsensus(params, false, "TestUTXOCommitment")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
// Mine chain of two blocks to fund our double spend
|
||||
firstBlockHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
firstBlockHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating firstBlock: %+v", err)
|
||||
}
|
||||
@@ -160,19 +161,19 @@ func TestDoubleSpends(t *testing.T) {
|
||||
// TestTransactionAcceptance checks that blue blocks transactions are favoured above
|
||||
// red blocks transactions, and that the block reward is paid only for blue blocks.
|
||||
func TestTransactionAcceptance(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
stagingArea := model.NewStagingArea()
|
||||
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
params.BlockCoinbaseMaturity = 0
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
testConsensus, teardown, err := factory.NewTestConsensus(consensusConfig, "TestTransactionAcceptance")
|
||||
testConsensus, teardown, err := factory.NewTestConsensus(params, false, "TestTransactionAcceptance")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up testConsensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
fundingBlock1Hash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
fundingBlock1Hash, _, err := testConsensus.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating fundingBlock1: %+v", err)
|
||||
}
|
||||
@@ -191,7 +192,7 @@ func TestTransactionAcceptance(t *testing.T) {
|
||||
// Add a chain of K blocks above fundingBlock3 so we'll
|
||||
// be able to mine a red block on top of it.
|
||||
tipHash := fundingBlock3Hash
|
||||
for i := model.KType(0); i < consensusConfig.K; i++ {
|
||||
for i := model.KType(0); i < params.K; i++ {
|
||||
var err error
|
||||
tipHash, _, err = testConsensus.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil)
|
||||
if err != nil {
|
||||
@@ -393,16 +394,16 @@ func TestTransactionAcceptance(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestResolveBlockStatusSanity(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
stagingArea := model.NewStagingArea()
|
||||
|
||||
consensus, teardown, err := consensus.NewFactory().NewTestConsensus(consensusConfig, "TestResolveBlockStatusSanity")
|
||||
consensus, teardown, err := consensus.NewFactory().NewTestConsensus(params, false, "TestResolveBlockStatusSanity")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
genesisHash := consensusConfig.GenesisHash
|
||||
genesisHash := params.GenesisHash
|
||||
allHashes := []*externalapi.DomainHash{genesisHash}
|
||||
|
||||
// Make sure that the status of genesisHash is valid
|
||||
@@ -414,7 +415,7 @@ func TestResolveBlockStatusSanity(t *testing.T) {
|
||||
t.Fatalf("genesis is unexpectedly non-valid. Its status is: %s", genesisStatus)
|
||||
}
|
||||
|
||||
chainLength := int(consensusConfig.K) + 1
|
||||
chainLength := int(params.K) + 1
|
||||
|
||||
// Add a chain of blocks over the genesis and make sure all their
|
||||
// statuses are valid
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
package consensusstatemanager
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util/staging"
|
||||
)
|
||||
|
||||
func (csm *consensusStateManager) ReverseUTXODiffs(tipHash *externalapi.DomainHash,
|
||||
reversalData *model.UTXODiffReversalData) error {
|
||||
|
||||
// During the process of resolving a chain of blocks, we temporarily set all blocks' (except the tip)
|
||||
// UTXODiffChild to be the selected parent.
|
||||
// Once the process is complete, we can reverse said chain, to now go directly to virtual through the relevant tip
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "reverseUTXODiffs")
|
||||
defer onEnd()
|
||||
|
||||
readStagingArea := model.NewStagingArea()
|
||||
|
||||
log.Debugf("Reversing utxoDiffs")
|
||||
|
||||
// Set previousUTXODiff and previousBlock to tip.SelectedParent before we start touching them,
|
||||
// since previousBlock's UTXODiff is going to be over-written in the next step
|
||||
previousBlock := reversalData.SelectedParentHash
|
||||
previousUTXODiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, readStagingArea, previousBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// tip.selectedParent is special in the sense that we don't have it's diff available in reverse, however,
|
||||
// we were able to calculate it when the tip's and tip.selectedParent's UTXOSets were known during resolveBlockStatus.
|
||||
// Therefore - we treat it separately
|
||||
err = csm.commitUTXODiffInSeparateStagingArea(previousBlock, reversalData.SelectedParentUTXODiff, tipHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Trace("Reversed 1 utxoDiff")
|
||||
|
||||
previousBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, readStagingArea, previousBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Now go over the rest of the blocks and assign for every block Bi.UTXODiff = Bi+1.UTXODiff.Reversed()
|
||||
for i := 1; ; i++ {
|
||||
currentBlock := previousBlockGHOSTDAGData.SelectedParent()
|
||||
|
||||
currentBlockUTXODiffChild, err := csm.utxoDiffStore.UTXODiffChild(csm.databaseContext, readStagingArea, currentBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, readStagingArea, currentBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// We stop reversing when current's UTXODiffChild is not current's SelectedParent
|
||||
if !currentBlockGHOSTDAGData.SelectedParent().Equal(currentBlockUTXODiffChild) {
|
||||
log.Debugf("Block %s's UTXODiffChild is not it's selected parent - finish reversing", currentBlock)
|
||||
break
|
||||
}
|
||||
|
||||
currentUTXODiff := previousUTXODiff.Reversed()
|
||||
|
||||
// retrieve current utxoDiff for Bi, to be used by next block
|
||||
previousUTXODiff, err = csm.utxoDiffStore.UTXODiff(csm.databaseContext, readStagingArea, currentBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = csm.commitUTXODiffInSeparateStagingArea(currentBlock, currentUTXODiff, previousBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
previousBlock = currentBlock
|
||||
previousBlockGHOSTDAGData = currentBlockGHOSTDAGData
|
||||
|
||||
log.Tracef("Reversed %d utxoDiffs", i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (csm *consensusStateManager) commitUTXODiffInSeparateStagingArea(
|
||||
blockHash *externalapi.DomainHash, utxoDiff externalapi.UTXODiff, utxoDiffChild *externalapi.DomainHash) error {
|
||||
|
||||
stagingAreaForCurrentBlock := model.NewStagingArea()
|
||||
|
||||
csm.utxoDiffStore.Stage(stagingAreaForCurrentBlock, blockHash, utxoDiff, utxoDiffChild)
|
||||
|
||||
return staging.CommitAllChanges(csm.databaseContext, stagingAreaForCurrentBlock)
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
package consensusstatemanager_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
)
|
||||
|
||||
func TestReverseUTXODiffs(t *testing.T) {
|
||||
// This test doesn't check ReverseUTXODiffs directly, since that would be quite complicated,
|
||||
// instead, it creates a situation where a reversal would defenitely happen - a reorg of 5 blocks,
|
||||
// then verifies that the resulting utxo-diffs and utxo-diff-children are all correct.
|
||||
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
factory := consensus.NewFactory()
|
||||
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestUTXOCommitment")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
// Create a chain of 5 blocks
|
||||
const initialChainLength = 5
|
||||
previousBlockHash := consensusConfig.GenesisHash
|
||||
for i := 0; i < initialChainLength; i++ {
|
||||
previousBlockHash, _, err = tc.AddBlock([]*externalapi.DomainHash{previousBlockHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error mining block no. %d in initial chain: %+v", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Mine a chain of 6 blocks, to re-organize the DAG
|
||||
const reorgChainLength = initialChainLength + 1
|
||||
reorgChain := make([]*externalapi.DomainHash, reorgChainLength)
|
||||
previousBlockHash = consensusConfig.GenesisHash
|
||||
for i := 0; i < reorgChainLength; i++ {
|
||||
previousBlockHash, _, err = tc.AddBlock([]*externalapi.DomainHash{previousBlockHash}, nil, nil)
|
||||
reorgChain[i] = previousBlockHash
|
||||
if err != nil {
|
||||
t.Fatalf("Error mining block no. %d in re-org chain: %+v", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
stagingArea := model.NewStagingArea()
|
||||
// Check that every block in the reorg chain has the next block as it's UTXODiffChild,
|
||||
// except that tip that has virtual, And that the diff is only `{ toRemove: { coinbase } }`
|
||||
for i, currentBlockHash := range reorgChain {
|
||||
if i == reorgChainLength-1 {
|
||||
hasUTXODiffChild, err := tc.UTXODiffStore().HasUTXODiffChild(tc.DatabaseContext(), stagingArea, currentBlockHash)
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting HasUTXODiffChild of %s: %+v", currentBlockHash, err)
|
||||
}
|
||||
if hasUTXODiffChild {
|
||||
t.Errorf("Block %s expected utxoDiffChild is virtual, but HasUTXODiffChild returned true",
|
||||
currentBlockHash)
|
||||
}
|
||||
} else {
|
||||
utxoDiffChild, err := tc.UTXODiffStore().UTXODiffChild(tc.DatabaseContext(), stagingArea, currentBlockHash)
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting utxoDiffChild of block No. %d, %s: %+v", i, currentBlockHash, err)
|
||||
}
|
||||
expectedUTXODiffChild := reorgChain[i+1]
|
||||
if !expectedUTXODiffChild.Equal(utxoDiffChild) {
|
||||
t.Errorf("Block %s expected utxoDiffChild is %s, but got %s instead",
|
||||
currentBlockHash, expectedUTXODiffChild, utxoDiffChild)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// skip the first block, since it's coinbase doesn't create outputs
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
currentBlock, err := tc.BlockStore().Block(tc.DatabaseContext(), stagingArea, currentBlockHash)
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting block %s: %+v", currentBlockHash, err)
|
||||
}
|
||||
utxoDiff, err := tc.UTXODiffStore().UTXODiff(tc.DatabaseContext(), stagingArea, currentBlockHash)
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting utxoDiffChild of %s: %+v", currentBlockHash, err)
|
||||
}
|
||||
if !checkIsUTXODiffOnlyRemoveCoinbase(t, utxoDiff, currentBlock) {
|
||||
t.Errorf("Expected %s to only have toRemove: {%s}, but got %s instead",
|
||||
currentBlockHash, consensushashing.TransactionID(currentBlock.Transactions[0]), utxoDiff)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func checkIsUTXODiffOnlyRemoveCoinbase(t *testing.T, utxoDiff externalapi.UTXODiff, currentBlock *externalapi.DomainBlock) bool {
|
||||
if utxoDiff.ToAdd().Len() > 0 || utxoDiff.ToRemove().Len() > 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
iterator := utxoDiff.ToRemove().Iterator()
|
||||
iterator.First()
|
||||
outpoint, _, err := iterator.Get()
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting from UTXODiff's iterator: %+v", err)
|
||||
}
|
||||
if !outpoint.TransactionID.Equal(consensushashing.TransactionID(currentBlock.Transactions[0])) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -22,8 +22,7 @@ func (csm *testConsensusStateManager) AddUTXOToMultiset(
|
||||
}
|
||||
|
||||
func (csm *testConsensusStateManager) ResolveBlockStatus(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash,
|
||||
useSeparateStagingAreaPerBlock bool) (externalapi.BlockStatus, error) {
|
||||
useSeparateStagingAreasPerBlock bool) (externalapi.BlockStatus, error) {
|
||||
|
||||
status, _, err := csm.resolveBlockStatus(stagingArea, blockHash, useSeparateStagingAreaPerBlock)
|
||||
return status, err
|
||||
return csm.resolveBlockStatus(stagingArea, blockHash, useSeparateStagingAreasPerBlock)
|
||||
}
|
||||
|
||||
@@ -10,13 +10,14 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
func TestConsensusStateManager_pickVirtualParents(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
stagingArea := model.NewStagingArea()
|
||||
|
||||
tc, teardown, err := consensus.NewFactory().NewTestConsensus(consensusConfig, "TestConsensusStateManager_pickVirtualParents")
|
||||
tc, teardown, err := consensus.NewFactory().NewTestConsensus(params, false, "TestConsensusStateManager_pickVirtualParents")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up tc: %+v", err)
|
||||
}
|
||||
@@ -41,14 +42,14 @@ func TestConsensusStateManager_pickVirtualParents(t *testing.T) {
|
||||
return virtualRelations.Parents
|
||||
}
|
||||
|
||||
// We build 2*consensusConfig.MaxBlockParents each one with blueWork higher than the other.
|
||||
parents := make([]*externalapi.DomainHash, 0, consensusConfig.MaxBlockParents)
|
||||
for i := 0; i < 2*int(consensusConfig.MaxBlockParents); i++ {
|
||||
lastBlock := consensusConfig.GenesisHash
|
||||
// We build 2*params.MaxBlockParents each one with blueWork higher than the other.
|
||||
parents := make([]*externalapi.DomainHash, 0, params.MaxBlockParents)
|
||||
for i := 0; i < 2*int(params.MaxBlockParents); i++ {
|
||||
lastBlock := params.GenesisHash
|
||||
for j := 0; j <= i; j++ {
|
||||
lastBlock, _, err = tc.AddBlock([]*externalapi.DomainHash{lastBlock}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed Adding block to tc: %+v", err)
|
||||
t.Fatalf("Failed Adding block to tc: %v", err)
|
||||
}
|
||||
}
|
||||
parents = append(parents, lastBlock)
|
||||
@@ -59,15 +60,15 @@ func TestConsensusStateManager_pickVirtualParents(t *testing.T) {
|
||||
|
||||
// Make sure the first half of the blocks are with highest blueWork
|
||||
// we use (max+1)/2 because the first "half" is rounded up, so `(dividend + (divisor - 1)) / divisor` = `(max + (2-1))/2` = `(max+1)/2`
|
||||
for i := 0; i < int(consensusConfig.MaxBlockParents+1)/2; i++ {
|
||||
for i := 0; i < int(params.MaxBlockParents+1)/2; i++ {
|
||||
if !virtualParents[i].Equal(parents[i]) {
|
||||
t.Fatalf("Expected block at %d to be equal, instead found %s != %s", i, virtualParents[i], parents[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the second half is the candidates with lowest blueWork
|
||||
end := len(parents) - int(consensusConfig.MaxBlockParents)/2
|
||||
for i := (consensusConfig.MaxBlockParents + 1) / 2; i < consensusConfig.MaxBlockParents; i++ {
|
||||
end := len(parents) - int(params.MaxBlockParents)/2
|
||||
for i := (params.MaxBlockParents + 1) / 2; i < params.MaxBlockParents; i++ {
|
||||
if !virtualParents[i].Equal(parents[end]) {
|
||||
t.Fatalf("Expected block at %d to be equal, instead found %s != %s", i, virtualParents[i], parents[end])
|
||||
}
|
||||
@@ -93,12 +94,12 @@ func TestConsensusStateManager_pickVirtualParents(t *testing.T) {
|
||||
break
|
||||
}
|
||||
}
|
||||
// build exactly consensusConfig.MaxBlockParents
|
||||
parents = make([]*externalapi.DomainHash, 0, consensusConfig.MaxBlockParents)
|
||||
for i := 0; i < int(consensusConfig.MaxBlockParents); i++ {
|
||||
// build exactly params.MaxBlockParents
|
||||
parents = make([]*externalapi.DomainHash, 0, params.MaxBlockParents)
|
||||
for i := 0; i < int(params.MaxBlockParents); i++ {
|
||||
block, _, err := tc.AddBlock([]*externalapi.DomainHash{virtualSelectedParent}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed Adding block to tc: %+v", err)
|
||||
t.Fatalf("Failed Adding block to tc: %v", err)
|
||||
}
|
||||
parents = append(parents, block)
|
||||
}
|
||||
|
||||
@@ -8,12 +8,13 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
func TestIsAncestorOf(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig, "TestIsAncestorOf")
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false, "TestIsAncestorOf")
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %s", err)
|
||||
}
|
||||
@@ -21,7 +22,7 @@ func TestIsAncestorOf(t *testing.T) {
|
||||
|
||||
// Add a chain of two blocks above the genesis. This will be the
|
||||
// selected parent chain.
|
||||
blockA, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
blockA, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -32,7 +33,7 @@ func TestIsAncestorOf(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add another block above the genesis
|
||||
blockC, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
blockC, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %s", err)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
const commonChainSize = 5
|
||||
@@ -16,18 +17,18 @@ const depth uint64 = 2
|
||||
|
||||
//TestBlockAtDepthOnChainDag compares the result of BlockAtDepth to the result of looping over the SelectedChain on a single chain DAG.
|
||||
func TestBlockAtDepthOnChainDag(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
stagingArea := model.NewStagingArea()
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig,
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false,
|
||||
"TestBlockAtDepthOnChainDag")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed creating a NewTestConsensus: %s", err)
|
||||
}
|
||||
defer tearDown(false)
|
||||
|
||||
highHash, err := createAChainDAG(consensusConfig.GenesisHash, tc)
|
||||
highHash, err := createAChainDAG(params.GenesisHash, tc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed creating a Chain DAG In BlockAtDepthTEST: %+v", err)
|
||||
}
|
||||
@@ -73,9 +74,9 @@ func createAChainDAG(genesisHash *externalapi.DomainHash, tc testapi.TestConsens
|
||||
// TestBlockAtDepthOnDAGWhereTwoBlocksHaveSameSelectedParent compares the results of BlockAtDepth
|
||||
// of 2 children that have the same selectedParent.
|
||||
func TestBlockAtDepthOnDAGWhereTwoBlocksHaveSameSelectedParent(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig,
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false,
|
||||
"TestBlockAtDepthOnDAGWhereTwoBlocksHaveSameSelectedParent")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed creating a NewTestConsensus: %s", err)
|
||||
@@ -84,7 +85,7 @@ func TestBlockAtDepthOnDAGWhereTwoBlocksHaveSameSelectedParent(t *testing.T) {
|
||||
|
||||
stagingArea := model.NewStagingArea()
|
||||
|
||||
firstChild, secondChild, err := createADAGTwoChildrenWithSameSelectedParent(consensusConfig.GenesisHash, tc)
|
||||
firstChild, secondChild, err := createADAGTwoChildrenWithSameSelectedParent(params.GenesisHash, tc)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed creating a DAG where two blocks have same selected parent: %+v", err)
|
||||
}
|
||||
@@ -127,9 +128,9 @@ func createADAGTwoChildrenWithSameSelectedParent(genesisHash *externalapi.Domain
|
||||
// TestBlockAtDepthOnDAGWithTwoDifferentChains compares results of BlockAtDepth on two different chains,
|
||||
// on the same DAG, and validates they merge at the correct point.
|
||||
func TestBlockAtDepthOnDAGWithTwoDifferentChains(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig,
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false,
|
||||
"TestBlockAtDepthOnDAGWithTwoDifferentChains")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed creating a NewTestConsensus: %s", err)
|
||||
@@ -139,7 +140,7 @@ func TestBlockAtDepthOnDAGWithTwoDifferentChains(t *testing.T) {
|
||||
const sizeOfTheFirstChildSubChainDAG = 3
|
||||
const sizeOfTheSecondChildSubChainDAG = 2
|
||||
|
||||
firstChild, secondChild, err := createADAGWithTwoDifferentChains(consensusConfig.GenesisHash, tc, sizeOfTheFirstChildSubChainDAG,
|
||||
firstChild, secondChild, err := createADAGWithTwoDifferentChains(params.GenesisHash, tc, sizeOfTheFirstChildSubChainDAG,
|
||||
sizeOfTheSecondChildSubChainDAG)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed creating a DAG with two different chains in BlockAtDepthTEST: %+v", err)
|
||||
@@ -206,10 +207,10 @@ func createADAGWithTwoDifferentChains(genesisHash *externalapi.DomainHash, tc te
|
||||
}
|
||||
|
||||
func TestLowestChainBlockAboveOrEqualToBlueScore(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.FinalityDuration = 10 * consensusConfig.TargetTimePerBlock
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
params.FinalityDuration = 10 * params.TargetTimePerBlock
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig,
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false,
|
||||
"TestLowestChainBlockAboveOrEqualToBlueScore")
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %s", err)
|
||||
@@ -240,8 +241,8 @@ func TestLowestChainBlockAboveOrEqualToBlueScore(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
chain := []*externalapi.DomainHash{consensusConfig.GenesisHash}
|
||||
tipHash := consensusConfig.GenesisHash
|
||||
chain := []*externalapi.DomainHash{params.GenesisHash}
|
||||
tipHash := params.GenesisHash
|
||||
for i := 0; i < 9; i++ {
|
||||
var err error
|
||||
tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil)
|
||||
@@ -252,7 +253,7 @@ func TestLowestChainBlockAboveOrEqualToBlueScore(t *testing.T) {
|
||||
chain = append(chain, tipHash)
|
||||
}
|
||||
|
||||
sideChain1TipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
sideChain1TipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -276,7 +277,7 @@ func TestLowestChainBlockAboveOrEqualToBlueScore(t *testing.T) {
|
||||
chain = append(chain, tipHash)
|
||||
}
|
||||
|
||||
sideChain2TipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
sideChain2TipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -301,7 +302,7 @@ func TestLowestChainBlockAboveOrEqualToBlueScore(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check by exact blue score
|
||||
checkExpectedBlock(tipHash, 0, consensusConfig.GenesisHash)
|
||||
checkExpectedBlock(tipHash, 0, params.GenesisHash)
|
||||
checkExpectedBlock(tipHash, 5, chain[5])
|
||||
checkExpectedBlock(tipHash, 19, chain[len(chain)-3])
|
||||
|
||||
|
||||
@@ -132,37 +132,37 @@ func TestBlockWindow(t *testing.T) {
|
||||
{
|
||||
parents: []string{"H", "F"},
|
||||
id: "I",
|
||||
expectedWindow: []string{"F", "D", "C", "H", "G", "B"},
|
||||
expectedWindow: []string{"F", "D", "H", "C", "G", "B"},
|
||||
},
|
||||
{
|
||||
parents: []string{"I"},
|
||||
id: "J",
|
||||
expectedWindow: []string{"I", "F", "D", "C", "H", "G", "B"},
|
||||
expectedWindow: []string{"I", "F", "D", "H", "C", "G", "B"},
|
||||
},
|
||||
{
|
||||
parents: []string{"J"},
|
||||
id: "K",
|
||||
expectedWindow: []string{"J", "I", "F", "D", "C", "H", "G", "B"},
|
||||
expectedWindow: []string{"J", "I", "F", "D", "H", "C", "G", "B"},
|
||||
},
|
||||
{
|
||||
parents: []string{"K"},
|
||||
id: "L",
|
||||
expectedWindow: []string{"K", "J", "I", "F", "D", "C", "H", "G", "B"},
|
||||
expectedWindow: []string{"K", "J", "I", "F", "D", "H", "C", "G", "B"},
|
||||
},
|
||||
{
|
||||
parents: []string{"L"},
|
||||
id: "M",
|
||||
expectedWindow: []string{"L", "K", "J", "I", "F", "D", "C", "H", "G", "B"},
|
||||
expectedWindow: []string{"L", "K", "J", "I", "F", "D", "H", "C", "G", "B"},
|
||||
},
|
||||
{
|
||||
parents: []string{"M"},
|
||||
id: "N",
|
||||
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "D", "C", "H", "G"},
|
||||
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "G"},
|
||||
},
|
||||
{
|
||||
parents: []string{"N"},
|
||||
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.DevnetParams.Name: {
|
||||
@@ -310,10 +310,10 @@ func TestBlockWindow(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.K = 1
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
params.K = 1
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig, "TestBlockWindow")
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false, "TestBlockWindow")
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %s", err)
|
||||
}
|
||||
@@ -322,10 +322,10 @@ func TestBlockWindow(t *testing.T) {
|
||||
windowSize := 10
|
||||
blockByIDMap := make(map[string]*externalapi.DomainHash)
|
||||
idByBlockMap := make(map[externalapi.DomainHash]string)
|
||||
blockByIDMap["A"] = consensusConfig.GenesisHash
|
||||
idByBlockMap[*consensusConfig.GenesisHash] = "A"
|
||||
blockByIDMap["A"] = params.GenesisHash
|
||||
idByBlockMap[*params.GenesisHash] = "A"
|
||||
|
||||
blocksData := tests[consensusConfig.Name]
|
||||
blocksData := tests[params.Name]
|
||||
|
||||
for _, blockData := range blocksData {
|
||||
parents := hashset.New()
|
||||
|
||||
@@ -18,23 +18,23 @@ import (
|
||||
)
|
||||
|
||||
func TestDifficulty(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
if consensusConfig.DisableDifficultyAdjustment {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
if params.DisableDifficultyAdjustment {
|
||||
return
|
||||
}
|
||||
// This test generates 3066 blocks above genesis with at least 1 second between each block, amounting to
|
||||
// a bit less then an hour of timestamps.
|
||||
// To prevent rejected blocks due to timestamps in the future, the following safeguard makes sure
|
||||
// the genesis block is at least 1 hour in the past.
|
||||
if consensusConfig.GenesisBlock.Header.TimeInMilliseconds() > mstime.ToMSTime(time.Now().Add(-time.Hour)).UnixMilliseconds() {
|
||||
if params.GenesisBlock.Header.TimeInMilliseconds() > mstime.ToMSTime(time.Now().Add(-time.Hour)).UnixMilliseconds() {
|
||||
t.Fatalf("TestDifficulty requires the GenesisBlock to be at least 1 hour old to pass")
|
||||
}
|
||||
|
||||
consensusConfig.K = 1
|
||||
consensusConfig.DifficultyAdjustmentWindowSize = 264
|
||||
params.K = 1
|
||||
params.DifficultyAdjustmentWindowSize = 264
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestDifficulty")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestDifficulty")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func TestDifficulty(t *testing.T) {
|
||||
t.Fatalf("BlockHeader: %+v", err)
|
||||
}
|
||||
|
||||
blockTime = header.TimeInMilliseconds() + consensusConfig.TargetTimePerBlock.Milliseconds()
|
||||
blockTime = header.TimeInMilliseconds() + params.TargetTimePerBlock.Milliseconds()
|
||||
}
|
||||
|
||||
block, _, err := tc.BuildBlockWithParents(parents, nil, nil)
|
||||
@@ -99,18 +99,18 @@ func TestDifficulty(t *testing.T) {
|
||||
return addBlock(minTime, parents...)
|
||||
}
|
||||
|
||||
tipHash := consensusConfig.GenesisHash
|
||||
tip := consensusConfig.GenesisBlock
|
||||
for i := 0; i < consensusConfig.DifficultyAdjustmentWindowSize; i++ {
|
||||
tipHash := params.GenesisHash
|
||||
tip := params.GenesisBlock
|
||||
for i := 0; i < params.DifficultyAdjustmentWindowSize; i++ {
|
||||
tip, tipHash = addBlock(0, tipHash)
|
||||
if tip.Header.Bits() != consensusConfig.GenesisBlock.Header.Bits() {
|
||||
if tip.Header.Bits() != params.GenesisBlock.Header.Bits() {
|
||||
t.Fatalf("As long as the block blue score is less then the difficulty adjustment " +
|
||||
"window size, the difficulty should be the same as genesis'")
|
||||
}
|
||||
}
|
||||
for i := 0; i < consensusConfig.DifficultyAdjustmentWindowSize+100; i++ {
|
||||
for i := 0; i < params.DifficultyAdjustmentWindowSize+100; i++ {
|
||||
tip, tipHash = addBlock(0, tipHash)
|
||||
if tip.Header.Bits() != consensusConfig.GenesisBlock.Header.Bits() {
|
||||
if tip.Header.Bits() != params.GenesisBlock.Header.Bits() {
|
||||
t.Fatalf("As long as the block rate remains the same, the difficulty shouldn't change")
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,7 @@ func TestDifficulty(t *testing.T) {
|
||||
}
|
||||
|
||||
var expectedBits uint32
|
||||
switch consensusConfig.Name {
|
||||
switch params.Name {
|
||||
case dagconfig.TestnetParams.Name, dagconfig.DevnetParams.Name:
|
||||
expectedBits = uint32(0x1e7f83df)
|
||||
case dagconfig.MainnetParams.Name:
|
||||
@@ -140,7 +140,7 @@ func TestDifficulty(t *testing.T) {
|
||||
}
|
||||
|
||||
// Increase block rate to increase difficulty
|
||||
for i := 0; i < consensusConfig.DifficultyAdjustmentWindowSize; i++ {
|
||||
for i := 0; i < params.DifficultyAdjustmentWindowSize; i++ {
|
||||
tip, tipHash = addBlockWithMinimumTime(tipHash)
|
||||
tipGHOSTDAGData, err := tc.GHOSTDAGDataStore().Get(tc.DatabaseContext(), stagingArea, tipHash)
|
||||
if err != nil {
|
||||
@@ -161,7 +161,7 @@ func TestDifficulty(t *testing.T) {
|
||||
// Add blocks until difficulty stabilizes
|
||||
lastBits := tip.Header.Bits()
|
||||
sameBitsCount := 0
|
||||
for sameBitsCount < consensusConfig.DifficultyAdjustmentWindowSize+1 {
|
||||
for sameBitsCount < params.DifficultyAdjustmentWindowSize+1 {
|
||||
tip, tipHash = addBlock(0, tipHash)
|
||||
if tip.Header.Bits() == lastBits {
|
||||
sameBitsCount++
|
||||
@@ -171,7 +171,7 @@ func TestDifficulty(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
slowBlockTime := tip.Header.TimeInMilliseconds() + consensusConfig.TargetTimePerBlock.Milliseconds() + 1000
|
||||
slowBlockTime := tip.Header.TimeInMilliseconds() + params.TargetTimePerBlock.Milliseconds() + 1000
|
||||
slowBlock, tipHash := addBlock(slowBlockTime, tipHash)
|
||||
if slowBlock.Header.Bits() != tip.Header.Bits() {
|
||||
t.Fatalf("The difficulty should only change when slowBlock is in the past of a block")
|
||||
@@ -192,7 +192,7 @@ func TestDifficulty(t *testing.T) {
|
||||
// blocks in its past and one without.
|
||||
splitBlockHash := tipHash
|
||||
blueTipHash := splitBlockHash
|
||||
for i := 0; i < consensusConfig.DifficultyAdjustmentWindowSize; i++ {
|
||||
for i := 0; i < params.DifficultyAdjustmentWindowSize; i++ {
|
||||
_, blueTipHash = addBlock(0, blueTipHash)
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ func TestDifficulty(t *testing.T) {
|
||||
// out the red blocks from the window, and check that the red blocks don't
|
||||
// affect the difficulty.
|
||||
blueTipHash = splitBlockHash
|
||||
for i := 0; i < consensusConfig.DifficultyAdjustmentWindowSize+redChainLength+1; i++ {
|
||||
for i := 0; i < params.DifficultyAdjustmentWindowSize+redChainLength+1; i++ {
|
||||
_, blueTipHash = addBlock(0, blueTipHash)
|
||||
}
|
||||
|
||||
@@ -230,24 +230,24 @@ func TestDifficulty(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDAAScore(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.DifficultyAdjustmentWindowSize = 264
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
params.DifficultyAdjustmentWindowSize = 264
|
||||
|
||||
stagingArea := model.NewStagingArea()
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestDifficulty")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestDifficulty")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
// We create a small DAG in order to skip from block with blue score of 1 directly to 3
|
||||
split1Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
split1Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
block, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
block, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -287,7 +287,7 @@ func TestDAAScore(t *testing.T) {
|
||||
|
||||
split2Hash := tipHash
|
||||
split2DAAScore := tipDAAScore
|
||||
for i := uint64(0); i < uint64(consensusConfig.DifficultyAdjustmentWindowSize)-1; i++ {
|
||||
for i := uint64(0); i < uint64(params.DifficultyAdjustmentWindowSize)-1; i++ {
|
||||
tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
@@ -309,7 +309,7 @@ func TestDAAScore(t *testing.T) {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
// This block is in the anticone of consensusConfig.DifficultyAdjustmentWindowSize-1 blocks, so it must be part
|
||||
// This block is in the anticone of params.DifficultyAdjustmentWindowSize-1 blocks, so it must be part
|
||||
// of the DAA window of a merging block
|
||||
blockAboveSplit2, _, err := tc.AddBlock([]*externalapi.DomainHash{split2Hash}, nil, nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package ghostdag2
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/kaspanet/kaspad/util/difficulty"
|
||||
"sort"
|
||||
|
||||
"math/big"
|
||||
|
||||
@@ -19,7 +18,7 @@ type ghostdagHelper struct {
|
||||
headerStore model.BlockHeaderStore
|
||||
}
|
||||
|
||||
// New creates a new instance of this alternative ghostdag impl
|
||||
// New creates a new instance of this alternative GHOSTDAG impl
|
||||
func New(
|
||||
databaseContext model.DBReader,
|
||||
dagTopologyManager model.DAGTopologyManager,
|
||||
@@ -36,53 +35,60 @@ func New(
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------- */
|
||||
|
||||
func (gh *ghostdagHelper) GHOSTDAG(stagingArea *model.StagingArea, blockCandidate *externalapi.DomainHash) error {
|
||||
myWork := new(big.Int)
|
||||
maxWork := new(big.Int)
|
||||
var myScore uint64
|
||||
var spScore uint64
|
||||
/* find the selectedParent */
|
||||
blockParents, err := gh.dagTopologyManager.Parents(stagingArea, blockCandidate)
|
||||
var blueScore uint64 = 0
|
||||
var blueWork = new(big.Int)
|
||||
blueWork.SetUint64(0)
|
||||
var selectedParent *externalapi.DomainHash = nil
|
||||
var mergeSetBlues = make([]*externalapi.DomainHash, 0)
|
||||
var mergeSetReds = make([]*externalapi.DomainHash, 0)
|
||||
|
||||
parents, err := gh.dagTopologyManager.Parents(stagingArea, blockCandidate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var selectedParent = blockParents[0]
|
||||
for _, parent := range blockParents {
|
||||
blockData, err := gh.dataStore.Get(gh.dbAccess, stagingArea, parent)
|
||||
// If genesis:
|
||||
if len(parents) == 0 {
|
||||
blockGHOSTDAGData := model.NewBlockGHOSTDAGData(blueScore, blueWork, selectedParent, mergeSetBlues, mergeSetReds, nil)
|
||||
gh.dataStore.Stage(stagingArea, blockCandidate, blockGHOSTDAGData)
|
||||
return nil
|
||||
}
|
||||
|
||||
maxBlueWork := new(big.Int)
|
||||
maxBlueWork.SetUint64(0)
|
||||
maxBlueScore := uint64(0)
|
||||
selectedParent = parents[0]
|
||||
// Find the selected parent.
|
||||
for _, parent := range parents {
|
||||
parentBlockData, err := gh.dataStore.Get(gh.dbAccess, stagingArea, parent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
blockWork := blockData.BlueWork()
|
||||
blockScore := blockData.BlueScore()
|
||||
if blockWork.Cmp(maxWork) == 1 {
|
||||
parentBlueWork := parentBlockData.BlueWork()
|
||||
switch parentBlueWork.Cmp(maxBlueWork) {
|
||||
case 0:
|
||||
if isMoreHash(parent, selectedParent) {
|
||||
selectedParent = parent
|
||||
maxBlueWork = parentBlueWork
|
||||
maxBlueScore = parentBlockData.BlueScore()
|
||||
}
|
||||
case 1:
|
||||
selectedParent = parent
|
||||
maxWork = blockWork
|
||||
spScore = blockScore
|
||||
}
|
||||
if blockWork.Cmp(maxWork) == 0 && ismoreHash(parent, selectedParent) {
|
||||
selectedParent = parent
|
||||
maxWork = blockWork
|
||||
spScore = blockScore
|
||||
maxBlueWork = parentBlueWork
|
||||
maxBlueScore = parentBlockData.BlueScore()
|
||||
}
|
||||
}
|
||||
myWork.Set(maxWork)
|
||||
myScore = spScore
|
||||
|
||||
/* Goal: iterate blockCandidate's mergeSet and divide it to : blue, blues, reds. */
|
||||
var mergeSetBlues = make([]*externalapi.DomainHash, 0)
|
||||
var mergeSetReds = make([]*externalapi.DomainHash, 0)
|
||||
var blueSet = make([]*externalapi.DomainHash, 0)
|
||||
blueWork.Set(maxBlueWork)
|
||||
blueScore = maxBlueScore
|
||||
|
||||
blueSet := make([]*externalapi.DomainHash, 0)
|
||||
blueSet = append(blueSet, selectedParent)
|
||||
mergeSetBlues = append(mergeSetBlues, selectedParent)
|
||||
|
||||
mergeSetArr, err := gh.findMergeSet(stagingArea, blockParents, selectedParent)
|
||||
mergeSet, err := gh.findMergeSet(stagingArea, parents, selectedParent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = gh.sortByBlueWork(stagingArea, mergeSetArr)
|
||||
err = gh.sortByBlueWork(stagingArea, mergeSet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -90,41 +96,36 @@ func (gh *ghostdagHelper) GHOSTDAG(stagingArea *model.StagingArea, blockCandidat
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, mergeSetBlock := range mergeSetArr {
|
||||
// Iterate on mergeSet and divide it to mergeSetBlues and mergeSetReds.
|
||||
for _, mergeSetBlock := range mergeSet {
|
||||
if mergeSetBlock.Equal(selectedParent) {
|
||||
if !contains(selectedParent, mergeSetBlues) {
|
||||
mergeSetBlues = append(mergeSetBlues, selectedParent)
|
||||
blueSet = append(blueSet, selectedParent)
|
||||
}
|
||||
continue
|
||||
}
|
||||
err := gh.divideBlueRed(stagingArea, selectedParent, mergeSetBlock, &mergeSetBlues, &mergeSetReds, &blueSet)
|
||||
err := gh.divideToBlueAndRed(stagingArea, mergeSetBlock, &mergeSetBlues, &mergeSetReds, &blueSet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
myScore += uint64(len(mergeSetBlues))
|
||||
blueScore += uint64(len(mergeSetBlues))
|
||||
|
||||
// We add up all the *work*(not blueWork) that all our blues and selected parent did
|
||||
// Calculation of blue work
|
||||
for _, blue := range mergeSetBlues {
|
||||
header, err := gh.headerStore.BlockHeader(gh.dbAccess, stagingArea, blue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
myWork.Add(myWork, difficulty.CalcWork(header.Bits()))
|
||||
blueWork.Add(blueWork, difficulty.CalcWork(header.Bits()))
|
||||
}
|
||||
|
||||
e := model.NewBlockGHOSTDAGData(myScore, myWork, selectedParent, mergeSetBlues, mergeSetReds, nil)
|
||||
gh.dataStore.Stage(stagingArea, blockCandidate, e)
|
||||
blockGHOSTDAGData := model.NewBlockGHOSTDAGData(blueScore, blueWork, selectedParent, mergeSetBlues, mergeSetReds, nil)
|
||||
gh.dataStore.Stage(stagingArea, blockCandidate, blockGHOSTDAGData)
|
||||
return nil
|
||||
}
|
||||
|
||||
/* --------isMoreHash(w, selectedParent)----------------*/
|
||||
func ismoreHash(parent *externalapi.DomainHash, selectedParent *externalapi.DomainHash) bool {
|
||||
func isMoreHash(parent *externalapi.DomainHash, selectedParent *externalapi.DomainHash) bool {
|
||||
parentByteArray := parent.ByteArray()
|
||||
selectedParentByteArray := selectedParent.ByteArray()
|
||||
//Check if parentHash is more then selectedParentHash
|
||||
|
||||
for i := 0; i < len(parentByteArray); i++ {
|
||||
switch {
|
||||
case parentByteArray[i] < selectedParentByteArray[i]:
|
||||
@@ -136,46 +137,39 @@ func ismoreHash(parent *externalapi.DomainHash, selectedParent *externalapi.Doma
|
||||
return false
|
||||
}
|
||||
|
||||
/* 1. blue = selectedParent.blue + blues
|
||||
2. not connected to at most K blocks (from the blue group)
|
||||
3. for each block at blue , check if not destroy
|
||||
*/
|
||||
|
||||
/* ---------------divideBluesReds--------------------- */
|
||||
func (gh *ghostdagHelper) divideBlueRed(stagingArea *model.StagingArea,
|
||||
selectedParent *externalapi.DomainHash, desiredBlock *externalapi.DomainHash,
|
||||
func (gh *ghostdagHelper) divideToBlueAndRed(stagingArea *model.StagingArea, blockToCheck *externalapi.DomainHash,
|
||||
blues *[]*externalapi.DomainHash, reds *[]*externalapi.DomainHash, blueSet *[]*externalapi.DomainHash) error {
|
||||
|
||||
var k = int(gh.k)
|
||||
counter := 0
|
||||
|
||||
var suspectsBlues = make([]*externalapi.DomainHash, 0)
|
||||
anticoneBlocksCounter := 0
|
||||
anticoneBlues := make([]*externalapi.DomainHash, 0)
|
||||
isMergeBlue := true
|
||||
|
||||
//check that not-connected to at most k.
|
||||
for _, block := range *blueSet {
|
||||
isAnticone, err := gh.isAnticone(stagingArea, block, desiredBlock)
|
||||
for _, blueblock := range *blueSet {
|
||||
isAnticone, err := gh.isAnticone(stagingArea, blueblock, blockToCheck)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isAnticone {
|
||||
counter++
|
||||
suspectsBlues = append(suspectsBlues, block)
|
||||
anticoneBlocksCounter++
|
||||
anticoneBlues = append(anticoneBlues, blueblock)
|
||||
}
|
||||
if counter > k {
|
||||
if anticoneBlocksCounter > k {
|
||||
isMergeBlue = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isMergeBlue {
|
||||
if !contains(desiredBlock, *reds) {
|
||||
*reds = append(*reds, desiredBlock)
|
||||
if !contains(blockToCheck, *reds) {
|
||||
*reds = append(*reds, blockToCheck)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// check that the k-cluster of each blue is still valid.
|
||||
for _, blue := range suspectsBlues {
|
||||
isDestroyed, err := gh.checkIfDestroy(stagingArea, blue, blueSet)
|
||||
// check that the k-cluster of each anticone blue block is still valid.
|
||||
for _, blueBlock := range anticoneBlues {
|
||||
isDestroyed, err := gh.checkIfDestroy(stagingArea, blueBlock, blueSet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -185,39 +179,37 @@ func (gh *ghostdagHelper) divideBlueRed(stagingArea *model.StagingArea,
|
||||
}
|
||||
}
|
||||
if !isMergeBlue {
|
||||
if !contains(desiredBlock, *reds) {
|
||||
*reds = append(*reds, desiredBlock)
|
||||
if !contains(blockToCheck, *reds) {
|
||||
*reds = append(*reds, blockToCheck)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if !contains(desiredBlock, *blues) {
|
||||
*blues = append(*blues, desiredBlock)
|
||||
if !contains(blockToCheck, *blues) {
|
||||
*blues = append(*blues, blockToCheck)
|
||||
}
|
||||
if !contains(desiredBlock, *blueSet) {
|
||||
*blueSet = append(*blueSet, desiredBlock)
|
||||
if !contains(blockToCheck, *blueSet) {
|
||||
*blueSet = append(*blueSet, blockToCheck)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/* ---------------isAnticone-------------------------- */
|
||||
func (gh *ghostdagHelper) isAnticone(stagingArea *model.StagingArea, blockA, blockB *externalapi.DomainHash) (bool, error) {
|
||||
isAAncestorOfAB, err := gh.dagTopologyManager.IsAncestorOf(stagingArea, blockA, blockB)
|
||||
isBlockAAncestorOfBlockB, err := gh.dagTopologyManager.IsAncestorOf(stagingArea, blockA, blockB)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
isBAncestorOfA, err := gh.dagTopologyManager.IsAncestorOf(stagingArea, blockB, blockA)
|
||||
isBlockBAncestorOfBlockA, err := gh.dagTopologyManager.IsAncestorOf(stagingArea, blockB, blockA)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return !isAAncestorOfAB && !isBAncestorOfA, nil
|
||||
|
||||
return !isBlockAAncestorOfBlockB && !isBlockBAncestorOfBlockA, nil
|
||||
}
|
||||
|
||||
/* ----------------validateKCluster------------------- */
|
||||
func (gh *ghostdagHelper) validateKCluster(stagingArea *model.StagingArea, chain *externalapi.DomainHash,
|
||||
checkedBlock *externalapi.DomainHash, counter *int, blueSet *[]*externalapi.DomainHash) (bool, error) {
|
||||
func (gh *ghostdagHelper) validateKCluster(stagingArea *model.StagingArea, chain *externalapi.DomainHash, checkedBlock *externalapi.DomainHash,
|
||||
counter *int, blueSet *[]*externalapi.DomainHash) (bool, error) {
|
||||
|
||||
var k = int(gh.k)
|
||||
k := int(gh.k)
|
||||
isAnticone, err := gh.isAnticone(stagingArea, chain, checkedBlock)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -236,6 +228,7 @@ func (gh *ghostdagHelper) validateKCluster(stagingArea *model.StagingArea, chain
|
||||
*counter++
|
||||
return true, nil
|
||||
}
|
||||
|
||||
isAncestorOf, err := gh.dagTopologyManager.IsAncestorOf(stagingArea, checkedBlock, chain)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -251,27 +244,24 @@ func (gh *ghostdagHelper) validateKCluster(stagingArea *model.StagingArea, chain
|
||||
} else {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
/*----------------contains-------------------------- */
|
||||
func contains(item *externalapi.DomainHash, items []*externalapi.DomainHash) bool {
|
||||
for _, r := range items {
|
||||
if r.Equal(item) {
|
||||
func contains(desiredItem *externalapi.DomainHash, items []*externalapi.DomainHash) bool {
|
||||
for _, item := range items {
|
||||
if item.Equal(desiredItem) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/* ----------------checkIfDestroy------------------- */
|
||||
/* find number of not-connected in his blue*/
|
||||
// find number of not-connected in blueSet
|
||||
func (gh *ghostdagHelper) checkIfDestroy(stagingArea *model.StagingArea, blockBlue *externalapi.DomainHash,
|
||||
blueSet *[]*externalapi.DomainHash) (bool, error) {
|
||||
|
||||
// Goal: check that the K-cluster of each block in the blueSet is not destroyed when adding the block to the mergeSet.
|
||||
var k = int(gh.k)
|
||||
// check that the K-cluster of each block in the blueSet is not destroyed when adding the block to the mergeSet.
|
||||
k := int(gh.k)
|
||||
counter := 0
|
||||
for _, blue := range *blueSet {
|
||||
isAnticone, err := gh.isAnticone(stagingArea, blue, blockBlue)
|
||||
@@ -288,51 +278,45 @@ func (gh *ghostdagHelper) checkIfDestroy(stagingArea *model.StagingArea, blockBl
|
||||
return false, nil
|
||||
}
|
||||
|
||||
/* ----------------findMergeSet------------------- */
|
||||
func (gh *ghostdagHelper) findMergeSet(stagingArea *model.StagingArea, parents []*externalapi.DomainHash,
|
||||
selectedParent *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
|
||||
|
||||
allMergeSet := make([]*externalapi.DomainHash, 0)
|
||||
blockQueue := make([]*externalapi.DomainHash, 0)
|
||||
mergeSet := make([]*externalapi.DomainHash, 0)
|
||||
blocksQueue := make([]*externalapi.DomainHash, 0)
|
||||
for _, parent := range parents {
|
||||
if !contains(parent, blockQueue) {
|
||||
blockQueue = append(blockQueue, parent)
|
||||
if !contains(parent, blocksQueue) {
|
||||
blocksQueue = append(blocksQueue, parent)
|
||||
}
|
||||
|
||||
}
|
||||
for len(blockQueue) > 0 {
|
||||
block := blockQueue[0]
|
||||
blockQueue = blockQueue[1:]
|
||||
for len(blocksQueue) > 0 {
|
||||
block := blocksQueue[0]
|
||||
blocksQueue = blocksQueue[1:]
|
||||
if selectedParent.Equal(block) {
|
||||
if !contains(block, allMergeSet) {
|
||||
allMergeSet = append(allMergeSet, block)
|
||||
if !contains(block, mergeSet) {
|
||||
mergeSet = append(mergeSet, block)
|
||||
}
|
||||
continue
|
||||
}
|
||||
isancestorOf, err := gh.dagTopologyManager.IsAncestorOf(stagingArea, block, selectedParent)
|
||||
isAncestorOf, err := gh.dagTopologyManager.IsAncestorOf(stagingArea, block, selectedParent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isancestorOf {
|
||||
if isAncestorOf {
|
||||
continue
|
||||
}
|
||||
if !contains(block, allMergeSet) {
|
||||
allMergeSet = append(allMergeSet, block)
|
||||
if !contains(block, mergeSet) {
|
||||
mergeSet = append(mergeSet, block)
|
||||
}
|
||||
err = gh.insertParent(stagingArea, block, &blockQueue)
|
||||
err = gh.insertParent(stagingArea, block, &blocksQueue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
return allMergeSet, nil
|
||||
return mergeSet, nil
|
||||
}
|
||||
|
||||
/* ----------------insertParent------------------- */
|
||||
/* Insert all parents to the queue*/
|
||||
func (gh *ghostdagHelper) insertParent(stagingArea *model.StagingArea, child *externalapi.DomainHash,
|
||||
queue *[]*externalapi.DomainHash) error {
|
||||
|
||||
// Insert all parents to the queue
|
||||
func (gh *ghostdagHelper) insertParent(stagingArea *model.StagingArea, child *externalapi.DomainHash, queue *[]*externalapi.DomainHash) error {
|
||||
parents, err := gh.dagTopologyManager.Parents(stagingArea, child)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -346,8 +330,9 @@ func (gh *ghostdagHelper) insertParent(stagingArea *model.StagingArea, child *ex
|
||||
return nil
|
||||
}
|
||||
|
||||
/* ----------------findBlueSet------------------- */
|
||||
func (gh *ghostdagHelper) findBlueSet(stagingArea *model.StagingArea, blueSet *[]*externalapi.DomainHash, selectedParent *externalapi.DomainHash) error {
|
||||
func (gh *ghostdagHelper) findBlueSet(stagingArea *model.StagingArea, blueSet *[]*externalapi.DomainHash,
|
||||
selectedParent *externalapi.DomainHash) error {
|
||||
|
||||
for selectedParent != nil {
|
||||
if !contains(selectedParent, *blueSet) {
|
||||
*blueSet = append(*blueSet, selectedParent)
|
||||
@@ -368,44 +353,41 @@ func (gh *ghostdagHelper) findBlueSet(stagingArea *model.StagingArea, blueSet *[
|
||||
return nil
|
||||
}
|
||||
|
||||
/* ----------------sortByBlueScore------------------- */
|
||||
func (gh *ghostdagHelper) sortByBlueWork(stagingArea *model.StagingArea, arr []*externalapi.DomainHash) error {
|
||||
|
||||
var err error = nil
|
||||
var err error
|
||||
sort.Slice(arr, func(i, j int) bool {
|
||||
|
||||
blockLeft, error := gh.dataStore.Get(gh.dbAccess, stagingArea, arr[i])
|
||||
if error != nil {
|
||||
err = error
|
||||
blockLeft, err := gh.dataStore.Get(gh.dbAccess, stagingArea, arr[i])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
blockRight, error := gh.dataStore.Get(gh.dbAccess, stagingArea, arr[j])
|
||||
if error != nil {
|
||||
err = error
|
||||
blockRight, err := gh.dataStore.Get(gh.dbAccess, stagingArea, arr[j])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if blockLeft.BlueWork().Cmp(blockRight.BlueWork()) == -1 {
|
||||
return true
|
||||
}
|
||||
if blockLeft.BlueWork().Cmp(blockRight.BlueWork()) == 0 {
|
||||
return ismoreHash(arr[j], arr[i])
|
||||
return isMoreHash(arr[j], arr[i])
|
||||
}
|
||||
return false
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
/* --------------------------------------------- */
|
||||
|
||||
func (gh *ghostdagHelper) BlockData(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) (*model.BlockGHOSTDAGData, error) {
|
||||
return gh.dataStore.Get(gh.dbAccess, stagingArea, blockHash)
|
||||
}
|
||||
func (gh *ghostdagHelper) ChooseSelectedParent(stagingArea *model.StagingArea, blockHashes ...*externalapi.DomainHash) (*externalapi.DomainHash, error) {
|
||||
|
||||
func (gh *ghostdagHelper) ChooseSelectedParent(*model.StagingArea, ...*externalapi.DomainHash) (*externalapi.DomainHash, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (gh *ghostdagHelper) Less(blockHashA *externalapi.DomainHash, ghostdagDataA *model.BlockGHOSTDAGData, blockHashB *externalapi.DomainHash, ghostdagDataB *model.BlockGHOSTDAGData) bool {
|
||||
func (gh *ghostdagHelper) Less(*externalapi.DomainHash, *model.BlockGHOSTDAGData, *externalapi.DomainHash, *model.BlockGHOSTDAGData) bool {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (gh *ghostdagHelper) GetSortedMergeSet(*model.StagingArea, *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
@@ -9,15 +9,16 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/blockheader"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/util/difficulty"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdag2"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/blockheader"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/util/difficulty"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -57,7 +58,7 @@ func TestGHOSTDAG(t *testing.T) {
|
||||
{ghostdagmanager.New, "Original"},
|
||||
{ghostdag2.New, "Tal's impl"},
|
||||
}
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
dagTopology := &DAGTopologyManagerImpl{
|
||||
parentsMap: make(map[externalapi.DomainHash][]*externalapi.DomainHash),
|
||||
}
|
||||
@@ -71,7 +72,7 @@ func TestGHOSTDAG(t *testing.T) {
|
||||
}
|
||||
|
||||
blockGHOSTDAGDataGenesis := model.NewBlockGHOSTDAGData(0, new(big.Int), nil, nil, nil, nil)
|
||||
genesisHeader := consensusConfig.GenesisBlock.Header
|
||||
genesisHeader := params.GenesisBlock.Header
|
||||
genesisWork := difficulty.CalcWork(genesisHeader.Bits())
|
||||
|
||||
var testsCounter int
|
||||
@@ -94,7 +95,7 @@ func TestGHOSTDAG(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("TestGHOSTDAG:failed decoding json: %v", err)
|
||||
}
|
||||
consensusConfig.K = test.K
|
||||
params.K = test.K
|
||||
|
||||
genesisHash := *StringToDomainHash(test.GenesisID)
|
||||
|
||||
|
||||
@@ -8,14 +8,15 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestAddHeaderTip(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig, "TestAddHeaderTip")
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false, "TestAddHeaderTip")
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %s", err)
|
||||
}
|
||||
@@ -50,8 +51,8 @@ func TestAddHeaderTip(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
expectedSelectedChain := []*externalapi.DomainHash{consensusConfig.GenesisHash}
|
||||
tipHash := consensusConfig.GenesisHash
|
||||
expectedSelectedChain := []*externalapi.DomainHash{params.GenesisHash}
|
||||
tipHash := params.GenesisHash
|
||||
for i := 0; i < 10; i++ {
|
||||
var err error
|
||||
tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil)
|
||||
@@ -63,8 +64,8 @@ func TestAddHeaderTip(t *testing.T) {
|
||||
checkExpectedSelectedChain(expectedSelectedChain)
|
||||
}
|
||||
|
||||
expectedSelectedChain = []*externalapi.DomainHash{consensusConfig.GenesisHash}
|
||||
tipHash = consensusConfig.GenesisHash
|
||||
expectedSelectedChain = []*externalapi.DomainHash{params.GenesisHash}
|
||||
tipHash = params.GenesisHash
|
||||
for i := 0; i < 11; i++ {
|
||||
var err error
|
||||
tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil)
|
||||
|
||||
@@ -9,12 +9,13 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
func TestPastMedianTime(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig, "TestUpdateReindexRoot")
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false, "TestUpdateReindexRoot")
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %s", err)
|
||||
}
|
||||
@@ -22,8 +23,8 @@ func TestPastMedianTime(t *testing.T) {
|
||||
|
||||
numBlocks := uint32(300)
|
||||
blockHashes := make([]*externalapi.DomainHash, numBlocks)
|
||||
blockHashes[0] = consensusConfig.GenesisHash
|
||||
blockTime := consensusConfig.GenesisBlock.Header.TimeInMilliseconds()
|
||||
blockHashes[0] = params.GenesisHash
|
||||
blockTime := params.GenesisBlock.Header.TimeInMilliseconds()
|
||||
for i := uint32(1); i < numBlocks; i++ {
|
||||
blockTime += 1000
|
||||
block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{blockHashes[i-1]}, nil, nil)
|
||||
@@ -72,7 +73,7 @@ func TestPastMedianTime(t *testing.T) {
|
||||
}
|
||||
|
||||
millisecondsSinceGenesis := pastMedianTime -
|
||||
consensusConfig.GenesisBlock.Header.TimeInMilliseconds()
|
||||
params.GenesisBlock.Header.TimeInMilliseconds()
|
||||
|
||||
if millisecondsSinceGenesis != test.expectedMillisecondsSinceGenesis {
|
||||
t.Errorf("TestCalcPastMedianTime: expected past median time of block %v to be %v milliseconds "+
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestPruning(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
err := filepath.Walk("./testdata", func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -65,22 +65,22 @@ func TestPruning(t *testing.T) {
|
||||
t.Fatalf("TestPruning: failed decoding json: %v", err)
|
||||
}
|
||||
|
||||
consensusConfig.FinalityDuration = time.Duration(test.FinalityDepth) * consensusConfig.TargetTimePerBlock
|
||||
consensusConfig.MergeSetSizeLimit = test.MergeSetSizeLimit
|
||||
params.FinalityDuration = time.Duration(test.FinalityDepth) * params.TargetTimePerBlock
|
||||
params.MergeSetSizeLimit = test.MergeSetSizeLimit
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestPruning")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestPruning")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
blockIDToHash := map[string]*externalapi.DomainHash{
|
||||
"0": consensusConfig.GenesisHash,
|
||||
"0": params.GenesisHash,
|
||||
}
|
||||
|
||||
blockHashToID := map[externalapi.DomainHash]string{
|
||||
*consensusConfig.GenesisHash: "0",
|
||||
*params.GenesisHash: "0",
|
||||
}
|
||||
|
||||
stagingArea := model.NewStagingArea()
|
||||
@@ -133,7 +133,7 @@ func TestPruning(t *testing.T) {
|
||||
}
|
||||
|
||||
pruningPointID := blockHashToID[*pruningPoint]
|
||||
expectedPruningPoint := expectedPruningPointByNet[info.Name()][consensusConfig.Name]
|
||||
expectedPruningPoint := expectedPruningPointByNet[info.Name()][params.Name]
|
||||
if expectedPruningPoint != pruningPointID {
|
||||
t.Fatalf("%s: Expected pruning point to be %s but got %s", info.Name(), expectedPruningPoint, pruningPointID)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util/staging"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -31,11 +30,10 @@ type pruningManager struct {
|
||||
utxoDiffStore model.UTXODiffStore
|
||||
daaBlocksStore model.DAABlocksStore
|
||||
|
||||
isArchivalNode bool
|
||||
genesisHash *externalapi.DomainHash
|
||||
finalityInterval uint64
|
||||
pruningDepth uint64
|
||||
shouldSanityCheckPruningUTXOSet bool
|
||||
isArchivalNode bool
|
||||
genesisHash *externalapi.DomainHash
|
||||
finalityInterval uint64
|
||||
pruningDepth uint64
|
||||
}
|
||||
|
||||
// New instantiates a new PruningManager
|
||||
@@ -62,30 +60,28 @@ func New(
|
||||
genesisHash *externalapi.DomainHash,
|
||||
finalityInterval uint64,
|
||||
pruningDepth uint64,
|
||||
shouldSanityCheckPruningUTXOSet bool,
|
||||
) model.PruningManager {
|
||||
|
||||
return &pruningManager{
|
||||
databaseContext: databaseContext,
|
||||
dagTraversalManager: dagTraversalManager,
|
||||
dagTopologyManager: dagTopologyManager,
|
||||
consensusStateManager: consensusStateManager,
|
||||
consensusStateStore: consensusStateStore,
|
||||
ghostdagDataStore: ghostdagDataStore,
|
||||
pruningStore: pruningStore,
|
||||
blockStatusStore: blockStatusStore,
|
||||
multiSetStore: multiSetStore,
|
||||
acceptanceDataStore: acceptanceDataStore,
|
||||
blocksStore: blocksStore,
|
||||
blockHeaderStore: blockHeaderStore,
|
||||
utxoDiffStore: utxoDiffStore,
|
||||
headerSelectedTipStore: headerSelectedTipStore,
|
||||
daaBlocksStore: daaBlocksStore,
|
||||
isArchivalNode: isArchivalNode,
|
||||
genesisHash: genesisHash,
|
||||
pruningDepth: pruningDepth,
|
||||
finalityInterval: finalityInterval,
|
||||
shouldSanityCheckPruningUTXOSet: shouldSanityCheckPruningUTXOSet,
|
||||
databaseContext: databaseContext,
|
||||
dagTraversalManager: dagTraversalManager,
|
||||
dagTopologyManager: dagTopologyManager,
|
||||
consensusStateManager: consensusStateManager,
|
||||
consensusStateStore: consensusStateStore,
|
||||
ghostdagDataStore: ghostdagDataStore,
|
||||
pruningStore: pruningStore,
|
||||
blockStatusStore: blockStatusStore,
|
||||
multiSetStore: multiSetStore,
|
||||
acceptanceDataStore: acceptanceDataStore,
|
||||
blocksStore: blocksStore,
|
||||
blockHeaderStore: blockHeaderStore,
|
||||
utxoDiffStore: utxoDiffStore,
|
||||
headerSelectedTipStore: headerSelectedTipStore,
|
||||
daaBlocksStore: daaBlocksStore,
|
||||
isArchivalNode: isArchivalNode,
|
||||
genesisHash: genesisHash,
|
||||
pruningDepth: pruningDepth,
|
||||
finalityInterval: finalityInterval,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,6 +197,7 @@ func (pm *pruningManager) UpdatePruningPointByVirtual(stagingArea *model.Staging
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return pm.deletePastBlocks(stagingArea, newPruningPoint)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -326,14 +323,13 @@ func (pm *pruningManager) savePruningPoint(stagingArea *model.StagingArea, pruni
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.savePruningPoint")
|
||||
defer onEnd()
|
||||
|
||||
// If pruningPointHash is the genesis then there's no pruning point set right now.
|
||||
if !pruningPointHash.Equal(pm.genesisHash) {
|
||||
previousPruningPoint, err := pm.pruningStore.PruningPoint(pm.databaseContext, stagingArea)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pm.pruningStore.StagePreviousPruningPoint(stagingArea, previousPruningPoint)
|
||||
// TODO: This is an assert that takes ~30 seconds to run
|
||||
// It must be removed or optimized before launching testnet
|
||||
err := pm.validateUTXOSetFitsCommitment(stagingArea, pruningPointHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pm.pruningStore.StagePruningPoint(stagingArea, pruningPointHash)
|
||||
pm.pruningStore.StageStartUpdatingPruningPointUTXOSet(stagingArea)
|
||||
|
||||
@@ -435,7 +431,7 @@ func (pm *pruningManager) validateUTXOSetFitsCommitment(stagingArea *model.Stagi
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.validateUTXOSetFitsCommitment")
|
||||
defer onEnd()
|
||||
|
||||
utxoSetIterator, err := pm.pruningStore.PruningPointUTXOIterator(pm.databaseContext)
|
||||
utxoSetIterator, err := pm.consensusStateManager.RestorePastUTXOSetIterator(stagingArea, pruningPointHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -472,96 +468,6 @@ func (pm *pruningManager) validateUTXOSetFitsCommitment(stagingArea *model.Stagi
|
||||
return nil
|
||||
}
|
||||
|
||||
// This function takes 2 points (currentPruningHash, previousPruningHash) and traverses the UTXO diff children DAG
|
||||
// until it finds a common descendant, at the worse case this descendant will be the current SelectedTip.
|
||||
// it then creates 2 diffs, one from that descendant to previousPruningHash and another from that descendant to currentPruningHash
|
||||
// then using `DiffFrom` it converts these 2 diffs to a single diff from previousPruningHash to currentPruningHash.
|
||||
// this way should be the fastest way to get the difference between the 2 points, and should perform much better than restoring the full UTXO set.
|
||||
func (pm *pruningManager) calculateDiffBetweenPreviousAndCurrentPruningPoints(stagingArea *model.StagingArea, currentPruningHash *externalapi.DomainHash) (externalapi.UTXODiff, error) {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.calculateDiffBetweenPreviousAndCurrentPruningPoints")
|
||||
defer onEnd()
|
||||
if currentPruningHash.Equal(pm.genesisHash) {
|
||||
return utxo.NewUTXODiff(), nil
|
||||
}
|
||||
|
||||
previousPruningHash, err := pm.pruningStore.PreviousPruningPoint(pm.databaseContext, stagingArea)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
currentPruningGhostDAG, err := pm.ghostdagDataStore.Get(pm.databaseContext, stagingArea, currentPruningHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
previousPruningGhostDAG, err := pm.ghostdagDataStore.Get(pm.databaseContext, stagingArea, previousPruningHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
currentPruningCurrentDiffChild := currentPruningHash
|
||||
previousPruningCurrentDiffChild := previousPruningHash
|
||||
// We need to use BlueWork because it's the only thing that's monotonic in the whole DAG
|
||||
// We use the BlueWork to know which point is currently lower on the DAG so we can keep climbing its children,
|
||||
// that way we keep climbing on the lowest point until they both reach the exact same descendant
|
||||
currentPruningCurrentDiffChildBlueWork := currentPruningGhostDAG.BlueWork()
|
||||
previousPruningCurrentDiffChildBlueWork := previousPruningGhostDAG.BlueWork()
|
||||
|
||||
var diffsFromPrevious []externalapi.UTXODiff
|
||||
var diffsFromCurrent []externalapi.UTXODiff
|
||||
for {
|
||||
// if currentPruningCurrentDiffChildBlueWork > previousPruningCurrentDiffChildBlueWork
|
||||
if currentPruningCurrentDiffChildBlueWork.Cmp(previousPruningCurrentDiffChildBlueWork) == 1 {
|
||||
utxoDiff, err := pm.utxoDiffStore.UTXODiff(pm.databaseContext, stagingArea, previousPruningCurrentDiffChild)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
diffsFromPrevious = append(diffsFromPrevious, utxoDiff)
|
||||
previousPruningCurrentDiffChild, err = pm.utxoDiffStore.UTXODiffChild(pm.databaseContext, stagingArea, previousPruningCurrentDiffChild)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
diffChildGhostDag, err := pm.ghostdagDataStore.Get(pm.databaseContext, stagingArea, previousPruningCurrentDiffChild)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
previousPruningCurrentDiffChildBlueWork = diffChildGhostDag.BlueWork()
|
||||
} else if currentPruningCurrentDiffChild.Equal(previousPruningCurrentDiffChild) {
|
||||
break
|
||||
} else {
|
||||
utxoDiff, err := pm.utxoDiffStore.UTXODiff(pm.databaseContext, stagingArea, currentPruningCurrentDiffChild)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
diffsFromCurrent = append(diffsFromCurrent, utxoDiff)
|
||||
currentPruningCurrentDiffChild, err = pm.utxoDiffStore.UTXODiffChild(pm.databaseContext, stagingArea, currentPruningCurrentDiffChild)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
diffChildGhostDag, err := pm.ghostdagDataStore.Get(pm.databaseContext, stagingArea, currentPruningCurrentDiffChild)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
currentPruningCurrentDiffChildBlueWork = diffChildGhostDag.BlueWork()
|
||||
}
|
||||
}
|
||||
// The order in which we apply the diffs should be from top to bottom, but we traversed from bottom to top
|
||||
// so we apply the diffs in reverse order.
|
||||
oldDiff := utxo.NewMutableUTXODiff()
|
||||
for i := len(diffsFromPrevious) - 1; i >= 0; i-- {
|
||||
err = oldDiff.WithDiffInPlace(diffsFromPrevious[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
newDiff := utxo.NewMutableUTXODiff()
|
||||
for i := len(diffsFromCurrent) - 1; i >= 0; i-- {
|
||||
err = newDiff.WithDiffInPlace(diffsFromCurrent[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return oldDiff.DiffFrom(newDiff.ToImmutable())
|
||||
}
|
||||
|
||||
// finalityScore is the number of finality intervals passed since
|
||||
// the given block.
|
||||
func (pm *pruningManager) finalityScore(blueScore uint64) uint64 {
|
||||
@@ -610,7 +516,7 @@ func (pm *pruningManager) AppendImportedPruningPointUTXOs(outpointAndUTXOEntryPa
|
||||
return dbTx.Commit()
|
||||
}
|
||||
|
||||
func (pm *pruningManager) UpdatePruningPointIfRequired() error {
|
||||
func (pm *pruningManager) UpdatePruningPointUTXOSetIfRequired() error {
|
||||
hadStartedUpdatingPruningPointUTXOSet, err := pm.pruningStore.HadStartedUpdatingPruningPointUTXOSet(pm.databaseContext)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -620,7 +526,7 @@ func (pm *pruningManager) UpdatePruningPointIfRequired() error {
|
||||
}
|
||||
|
||||
log.Debugf("Pruning point UTXO set update is required")
|
||||
err = pm.updatePruningPoint()
|
||||
err = pm.updatePruningPointUTXOSet(model.NewStagingArea())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -629,14 +535,13 @@ func (pm *pruningManager) UpdatePruningPointIfRequired() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pm *pruningManager) updatePruningPoint() error {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "updatePruningPoint")
|
||||
func (pm *pruningManager) updatePruningPointUTXOSet(stagingArea *model.StagingArea) error {
|
||||
onEnd := logger.LogAndMeasureExecutionTime(log, "updatePruningPointUTXOSet")
|
||||
defer onEnd()
|
||||
|
||||
logger.LogMemoryStats(log, "updatePruningPoint start")
|
||||
defer logger.LogMemoryStats(log, "updatePruningPoint end")
|
||||
logger.LogMemoryStats(log, "updatePruningPointUTXOSet start")
|
||||
defer logger.LogMemoryStats(log, "updatePruningPointUTXOSet end")
|
||||
|
||||
stagingArea := model.NewStagingArea()
|
||||
log.Debugf("Getting the pruning point")
|
||||
pruningPoint, err := pm.pruningStore.PruningPoint(pm.databaseContext, stagingArea)
|
||||
if err != nil {
|
||||
@@ -644,27 +549,14 @@ func (pm *pruningManager) updatePruningPoint() error {
|
||||
}
|
||||
|
||||
log.Debugf("Restoring the pruning point UTXO set")
|
||||
utxoSetDiff, err := pm.calculateDiffBetweenPreviousAndCurrentPruningPoints(stagingArea, pruningPoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Debugf("Updating the pruning point UTXO set")
|
||||
err = pm.pruningStore.UpdatePruningPointUTXOSet(pm.databaseContext, utxoSetDiff)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pm.shouldSanityCheckPruningUTXOSet {
|
||||
err = pm.validateUTXOSetFitsCommitment(stagingArea, pruningPoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = pm.deletePastBlocks(stagingArea, pruningPoint)
|
||||
utxoSetIterator, err := pm.consensusStateManager.RestorePastUTXOSetIterator(stagingArea, pruningPoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer utxoSetIterator.Close()
|
||||
|
||||
err = staging.CommitAllChanges(pm.databaseContext, stagingArea)
|
||||
log.Debugf("Updating the pruning point UTXO set")
|
||||
err = pm.pruningStore.UpdatePruningPointUTXOSet(pm.databaseContext, utxoSetIterator)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -8,12 +8,13 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
func TestReachabilityIsDAGAncestorOf(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestReachabilityIsDAGAncestorOf")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestReachabilityIsDAGAncestorOf")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
@@ -24,7 +25,7 @@ func TestReachabilityIsDAGAncestorOf(t *testing.T) {
|
||||
// genesis \ \ sharedBlock
|
||||
// \ \ /
|
||||
// C <- D - - - - /
|
||||
genesisHash := consensusConfig.GenesisHash
|
||||
genesisHash := params.GenesisHash
|
||||
blockHashA, _, err := tc.AddBlock([]*externalapi.DomainHash{genesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %v", err)
|
||||
|
||||
@@ -9,13 +9,14 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *testing.T) {
|
||||
reachabilityReindexWindow := uint64(10)
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig,
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false,
|
||||
"TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot")
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %+v", err)
|
||||
@@ -31,12 +32,12 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t
|
||||
t.Fatalf("ReachabilityReindexRoot: %s", err)
|
||||
}
|
||||
|
||||
if !reindexRoot.Equal(consensusConfig.GenesisHash) {
|
||||
if !reindexRoot.Equal(params.GenesisHash) {
|
||||
t.Fatalf("reindex root is expected to initially be genesis")
|
||||
}
|
||||
|
||||
// Add a block on top of the genesis block
|
||||
chainRootBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
chainRootBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -66,13 +67,13 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t
|
||||
slackSize := tc.ReachabilityManager().ReachabilityReindexSlack()
|
||||
blocksToAdd := uint64(math.Log2(float64(slackSize))) + 2
|
||||
for i := uint64(0); i < blocksToAdd; i++ {
|
||||
_, _, err = tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
_, _, err = tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = tc.ReachabilityManager().ValidateIntervals(consensusConfig.GenesisHash)
|
||||
err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -81,9 +82,9 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t
|
||||
|
||||
func TestUpdateReindexRoot(t *testing.T) {
|
||||
reachabilityReindexWindow := uint64(10)
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig, "TestUpdateReindexRoot")
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false, "TestUpdateReindexRoot")
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %s", err)
|
||||
}
|
||||
@@ -102,12 +103,12 @@ func TestUpdateReindexRoot(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add two blocks on top of the genesis block
|
||||
chain1RootBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
chain1RootBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
chain2RootBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
chain2RootBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -131,7 +132,7 @@ func TestUpdateReindexRoot(t *testing.T) {
|
||||
t.Fatalf("ReachabilityReindexRoot: %s", err)
|
||||
}
|
||||
|
||||
if !reindexRoot.Equal(consensusConfig.GenesisHash) {
|
||||
if !reindexRoot.Equal(params.GenesisHash) {
|
||||
t.Fatalf("reindex root unexpectedly moved")
|
||||
}
|
||||
}
|
||||
@@ -162,14 +163,14 @@ func TestUpdateReindexRoot(t *testing.T) {
|
||||
|
||||
// Make sure that the rest of the interval has been allocated to
|
||||
// chain1RootNode, minus slack from both sides
|
||||
expectedChain1RootIntervalSize := intervalSize(consensusConfig.GenesisHash) - 1 -
|
||||
expectedChain1RootIntervalSize := intervalSize(params.GenesisHash) - 1 -
|
||||
intervalSize(chain2RootBlock) - 2*tc.ReachabilityManager().ReachabilityReindexSlack()
|
||||
if intervalSize(chain1RootBlock) != expectedChain1RootIntervalSize {
|
||||
t.Fatalf("got unexpected chain1RootBlock interval. Want: %d, got: %d",
|
||||
intervalSize(chain1RootBlock), expectedChain1RootIntervalSize)
|
||||
}
|
||||
|
||||
err = tc.ReachabilityManager().ValidateIntervals(consensusConfig.GenesisHash)
|
||||
err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -178,9 +179,9 @@ func TestUpdateReindexRoot(t *testing.T) {
|
||||
|
||||
func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
reachabilityReindexWindow := uint64(10)
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig, "TestUpdateReindexRoot")
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false, "TestUpdateReindexRoot")
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %+v", err)
|
||||
}
|
||||
@@ -199,17 +200,17 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
}
|
||||
|
||||
// Add three children to the genesis: leftBlock, centerBlock, rightBlock
|
||||
leftBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
leftBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
centerBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
centerBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
rightBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
rightBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -247,7 +248,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
t.Fatalf("rightBlock interval not tight after reindex")
|
||||
}
|
||||
|
||||
err = tc.ReachabilityManager().ValidateIntervals(consensusConfig.GenesisHash)
|
||||
err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -265,7 +266,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
err = tc.ReachabilityManager().ValidateIntervals(consensusConfig.GenesisHash)
|
||||
err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -283,13 +284,13 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
err = tc.ReachabilityManager().ValidateIntervals(consensusConfig.GenesisHash)
|
||||
err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
err = tc.ReachabilityManager().ValidateIntervals(consensusConfig.GenesisHash)
|
||||
err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -298,9 +299,9 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
|
||||
func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
reachabilityReindexWindow := uint64(10)
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig, "TestUpdateReindexRoot")
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false, "TestUpdateReindexRoot")
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %s", err)
|
||||
}
|
||||
@@ -310,7 +311,7 @@ func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
|
||||
// Add a chain of reachabilityReindexWindow + 1 blocks above the genesis.
|
||||
// This will set the reindex root to the child of genesis
|
||||
chainTipHash := consensusConfig.GenesisHash
|
||||
chainTipHash := params.GenesisHash
|
||||
for i := uint64(0); i < reachabilityReindexWindow+1; i++ {
|
||||
chainTipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{chainTipHash}, nil, nil)
|
||||
if err != nil {
|
||||
@@ -320,7 +321,7 @@ func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
|
||||
// Add another block above the genesis block. This will trigger an
|
||||
// earlier-than-reindex-root reindex
|
||||
sideBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
sideBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -332,7 +333,7 @@ func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
err = tc.ReachabilityManager().ValidateIntervals(consensusConfig.GenesisHash)
|
||||
err = tc.ReachabilityManager().ValidateIntervals(params.GenesisHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ const numBlocksExponent = 12
|
||||
|
||||
func initializeTest(t *testing.T, testName string) (tc testapi.TestConsensus, teardown func(keepDataDir bool)) {
|
||||
t.Parallel()
|
||||
consensusConfig := consensus.Config{Params: dagconfig.SimnetParams}
|
||||
consensusConfig.SkipProofOfWork = true
|
||||
tc, teardown, err := consensus.NewFactory().NewTestConsensus(&consensusConfig, testName)
|
||||
params := dagconfig.SimnetParams
|
||||
params.SkipProofOfWork = true
|
||||
tc, teardown, err := consensus.NewFactory().NewTestConsensus(¶ms, false, testName)
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
|
||||
@@ -8,22 +8,23 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestCreateBlockLocator(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig,
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false,
|
||||
"TestCreateBlockLocator")
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %+v", err)
|
||||
}
|
||||
defer tearDown(false)
|
||||
|
||||
chain := []*externalapi.DomainHash{consensusConfig.GenesisHash}
|
||||
tipHash := consensusConfig.GenesisHash
|
||||
chain := []*externalapi.DomainHash{params.GenesisHash}
|
||||
tipHash := params.GenesisHash
|
||||
for i := 0; i < 20; i++ {
|
||||
var err error
|
||||
tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil)
|
||||
@@ -34,13 +35,13 @@ func TestCreateBlockLocator(t *testing.T) {
|
||||
chain = append(chain, tipHash)
|
||||
}
|
||||
|
||||
sideChainTipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
sideChainTipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
// Check a situation where low hash is not on the exact step blue score
|
||||
locator, err := tc.CreateBlockLocator(consensusConfig.GenesisHash, tipHash, 0)
|
||||
locator, err := tc.CreateBlockLocator(params.GenesisHash, tipHash, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateBlockLocator: %+v", err)
|
||||
}
|
||||
@@ -73,7 +74,7 @@ func TestCreateBlockLocator(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check block locator with limit
|
||||
locator, err = tc.CreateBlockLocator(consensusConfig.GenesisHash, tipHash, 3)
|
||||
locator, err = tc.CreateBlockLocator(params.GenesisHash, tipHash, 3)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateBlockLocator: %+v", err)
|
||||
}
|
||||
@@ -87,13 +88,13 @@ func TestCreateBlockLocator(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check a block locator from genesis to genesis
|
||||
locator, err = tc.CreateBlockLocator(consensusConfig.GenesisHash, consensusConfig.GenesisHash, 0)
|
||||
locator, err = tc.CreateBlockLocator(params.GenesisHash, params.GenesisHash, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateBlockLocator: %+v", err)
|
||||
}
|
||||
|
||||
if !externalapi.HashesEqual(locator, []*externalapi.DomainHash{
|
||||
consensusConfig.GenesisHash,
|
||||
params.GenesisHash,
|
||||
}) {
|
||||
t.Fatalf("unexpected block locator %s", locator)
|
||||
}
|
||||
@@ -133,17 +134,17 @@ func TestCreateBlockLocator(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCreateHeadersSelectedChainBlockLocator(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig,
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false,
|
||||
"TestCreateHeadersSelectedChainBlockLocator")
|
||||
if err != nil {
|
||||
t.Fatalf("NewTestConsensus: %+v", err)
|
||||
}
|
||||
defer tearDown(false)
|
||||
|
||||
chain := []*externalapi.DomainHash{consensusConfig.GenesisHash}
|
||||
tipHash := consensusConfig.GenesisHash
|
||||
chain := []*externalapi.DomainHash{params.GenesisHash}
|
||||
tipHash := params.GenesisHash
|
||||
for i := 0; i < 20; i++ {
|
||||
var err error
|
||||
tipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil)
|
||||
@@ -154,13 +155,13 @@ func TestCreateHeadersSelectedChainBlockLocator(t *testing.T) {
|
||||
chain = append(chain, tipHash)
|
||||
}
|
||||
|
||||
sideChainTipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
sideChainTipHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
// Check a situation where low hash is not on the exact step
|
||||
locator, err := tc.CreateHeadersSelectedChainBlockLocator(consensusConfig.GenesisHash, tipHash)
|
||||
locator, err := tc.CreateHeadersSelectedChainBlockLocator(params.GenesisHash, tipHash)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateBlockLocator: %+v", err)
|
||||
}
|
||||
@@ -193,13 +194,13 @@ func TestCreateHeadersSelectedChainBlockLocator(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check a block locator from genesis to genesis
|
||||
locator, err = tc.CreateHeadersSelectedChainBlockLocator(consensusConfig.GenesisHash, consensusConfig.GenesisHash)
|
||||
locator, err = tc.CreateHeadersSelectedChainBlockLocator(params.GenesisHash, params.GenesisHash)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateBlockLocator: %+v", err)
|
||||
}
|
||||
|
||||
if !externalapi.HashesEqual(locator, []*externalapi.DomainHash{
|
||||
consensusConfig.GenesisHash,
|
||||
params.GenesisHash,
|
||||
}) {
|
||||
t.Fatalf("unexpected block locator %s", locator)
|
||||
}
|
||||
@@ -224,7 +225,7 @@ func TestCreateHeadersSelectedChainBlockLocator(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check block locator with non chain blocks
|
||||
_, err = tc.CreateHeadersSelectedChainBlockLocator(consensusConfig.GenesisHash, sideChainTipHash)
|
||||
_, err = tc.CreateHeadersSelectedChainBlockLocator(params.GenesisHash, sideChainTipHash)
|
||||
if !errors.Is(err, model.ErrBlockNotInSelectedParentChain) {
|
||||
t.Fatalf("expected error '%s' but got '%s'", database.ErrNotFound, err)
|
||||
}
|
||||
|
||||
@@ -11,14 +11,15 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
func TestSyncManager_GetHashesBetween(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
stagingArea := model.NewStagingArea()
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestSyncManager_GetHashesBetween")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestSyncManager_GetHashesBetween")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
@@ -35,7 +36,7 @@ func TestSyncManager_GetHashesBetween(t *testing.T) {
|
||||
// \ | /
|
||||
// etc.
|
||||
expectedOrder := make([]*externalapi.DomainHash, 0, 40)
|
||||
mergingBlock := consensusConfig.GenesisHash
|
||||
mergingBlock := params.GenesisHash
|
||||
for i := 0; i < 10; i++ {
|
||||
splitBlocks := make([]*externalapi.DomainHash, 0, 3)
|
||||
for j := 0; j < 3; j++ {
|
||||
@@ -69,7 +70,7 @@ func TestSyncManager_GetHashesBetween(t *testing.T) {
|
||||
}
|
||||
|
||||
actualOrder, _, err := tc.SyncManager().GetHashesBetween(
|
||||
stagingArea, consensusConfig.GenesisHash, expectedOrder[len(expectedOrder)-1], math.MaxUint64)
|
||||
stagingArea, params.GenesisHash, expectedOrder[len(expectedOrder)-1], math.MaxUint64)
|
||||
if err != nil {
|
||||
t.Fatalf("TestSyncManager_GetHashesBetween failed returning actualOrder: %v", err)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -21,9 +22,9 @@ type txSubnetworkData struct {
|
||||
}
|
||||
|
||||
func TestValidateTransactionInIsolation(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestValidateTransactionInIsolation")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestValidateTransactionInIsolation")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
@@ -78,7 +79,7 @@ func TestValidateTransactionInIsolation(t *testing.T) {
|
||||
1,
|
||||
1,
|
||||
subnetworks.SubnetworkIDNative,
|
||||
&txSubnetworkData{subnetworks.SubnetworkIDCoinbase, 0, make([]byte, consensusConfig.MaxCoinbasePayloadLength+1)},
|
||||
&txSubnetworkData{subnetworks.SubnetworkIDCoinbase, 0, make([]byte, params.MaxCoinbasePayloadLength+1)},
|
||||
nil,
|
||||
ruleerrors.ErrBadCoinbasePayloadLen},
|
||||
{"non-zero gas in Kaspa", 1, 1, 0,
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -29,7 +30,7 @@ func (mdf *mocPastMedianTimeManager) PastMedianTime(*model.StagingArea, *externa
|
||||
}
|
||||
|
||||
func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
pastMedianManager := &mocPastMedianTimeManager{}
|
||||
@@ -37,7 +38,7 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) {
|
||||
model.GHOSTDAGDataStore, *externalapi.DomainHash) model.PastMedianTimeManager {
|
||||
return pastMedianManager
|
||||
})
|
||||
tc, tearDown, err := factory.NewTestConsensus(consensusConfig,
|
||||
tc, tearDown, err := factory.NewTestConsensus(params, false,
|
||||
"TestValidateTransactionInContextAndPopulateMassAndFee")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed create a NewTestConsensus: %s", err)
|
||||
@@ -57,7 +58,7 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to serialize public key: %v", err)
|
||||
}
|
||||
addr, err := util.NewAddressPublicKey(publicKeySerialized[:], consensusConfig.Prefix)
|
||||
addr, err := util.NewAddressPublicKey(publicKeySerialized[:], params.Prefix)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate p2pk address: %v", err)
|
||||
}
|
||||
@@ -157,7 +158,7 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) {
|
||||
stagingArea := model.NewStagingArea()
|
||||
|
||||
povBlockHash := externalapi.NewDomainHashFromByteArray(&[32]byte{0x01})
|
||||
tc.DAABlocksStore().StageDAAScore(stagingArea, povBlockHash, consensusConfig.BlockCoinbaseMaturity+txInput.UTXOEntry.BlockDAAScore())
|
||||
tc.DAABlocksStore().StageDAAScore(stagingArea, povBlockHash, params.BlockCoinbaseMaturity+txInput.UTXOEntry.BlockDAAScore())
|
||||
tc.DAABlocksStore().StageDAAScore(stagingArea, povBlockHash, 10)
|
||||
|
||||
tests := []struct {
|
||||
@@ -239,10 +240,10 @@ func TestValidateTransactionInContextAndPopulateMassAndFee(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSigningTwoInputs(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
params.BlockCoinbaseMaturity = 0
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestSigningTwoInputs")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestSigningTwoInputs")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
@@ -260,7 +261,7 @@ func TestSigningTwoInputs(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to serialize public key: %v", err)
|
||||
}
|
||||
addr, err := util.NewAddressPublicKey(publicKeySerialized[:], consensusConfig.Prefix)
|
||||
addr, err := util.NewAddressPublicKey(publicKeySerialized[:], params.Prefix)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate p2pk address: %v", err)
|
||||
}
|
||||
@@ -274,7 +275,7 @@ func TestSigningTwoInputs(t *testing.T) {
|
||||
ScriptPublicKey: scriptPublicKey,
|
||||
}
|
||||
|
||||
block1Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, coinbaseData, nil)
|
||||
block1Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, coinbaseData, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
@@ -363,10 +364,10 @@ func TestSigningTwoInputs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSigningTwoInputsECDSA(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
params.BlockCoinbaseMaturity = 0
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestSigningTwoInputsECDSA")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestSigningTwoInputsECDSA")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up consensus: %+v", err)
|
||||
}
|
||||
@@ -384,7 +385,7 @@ func TestSigningTwoInputsECDSA(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to serialize public key: %v", err)
|
||||
}
|
||||
addr, err := util.NewAddressPublicKeyECDSA(publicKeySerialized[:], consensusConfig.Prefix)
|
||||
addr, err := util.NewAddressPublicKeyECDSA(publicKeySerialized[:], params.Prefix)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate p2pk address: %v", err)
|
||||
}
|
||||
@@ -398,7 +399,7 @@ func TestSigningTwoInputsECDSA(t *testing.T) {
|
||||
ScriptPublicKey: scriptPublicKey,
|
||||
}
|
||||
|
||||
block1Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, coinbaseData, nil)
|
||||
block1Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, coinbaseData, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("AddBlock: %+v", err)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package consensus_test
|
||||
package consensus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
@@ -15,13 +14,13 @@ func TestPruningDepth(t *testing.T) {
|
||||
dagconfig.DevnetParams.Name: 244838,
|
||||
dagconfig.SimnetParams.Name: 192038,
|
||||
}
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
expected, found := expectedResult[consensusConfig.Name]
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
expected, found := expectedResult[params.Name]
|
||||
if !found {
|
||||
t.Fatalf("TestPruningDepth: expectedResult doesn't contain '%s'", consensusConfig.Name)
|
||||
t.Fatalf("TestPruningDepth: expectedResult doesn't contain '%s'", params.Name)
|
||||
}
|
||||
if consensusConfig.PruningDepth() != expected {
|
||||
t.Errorf("pruningDepth in %s is expected to be %d but got %d", consensusConfig.Name, expected, consensusConfig.PruningDepth())
|
||||
if params.PruningDepth() != expected {
|
||||
t.Errorf("pruningDepth in %s is expected to be %d but got %d", params.Name, expected, params.PruningDepth())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ import (
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
)
|
||||
|
||||
// RenderDAGToDot is a helper function for debugging tests.
|
||||
@@ -30,7 +28,6 @@ func (tc *testConsensus) convertToDot() (string, error) {
|
||||
}
|
||||
defer blocksIterator.Close()
|
||||
|
||||
stagingArea := model.NewStagingArea()
|
||||
for ok := blocksIterator.First(); ok; ok = blocksIterator.Next() {
|
||||
hash, err := blocksIterator.Get()
|
||||
if err != nil {
|
||||
@@ -38,7 +35,7 @@ func (tc *testConsensus) convertToDot() (string, error) {
|
||||
}
|
||||
dotScriptBuilder.WriteString(fmt.Sprintf("\t\"%s\";\n", hash))
|
||||
|
||||
parents, err := tc.dagTopologyManager.Parents(stagingArea, hash)
|
||||
parents, err := tc.dagTopologyManager.Parents(nil, hash)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package mining
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/pow"
|
||||
"github.com/kaspanet/kaspad/util/difficulty"
|
||||
"math"
|
||||
"math/rand"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/pow"
|
||||
"github.com/kaspanet/kaspad/util/difficulty"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
||||
@@ -3,13 +3,12 @@ package testutils
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
)
|
||||
|
||||
// ForAllNets runs the passed testFunc with all available networks
|
||||
// if setDifficultyToMinumum = true - will modify the net params to have minimal difficulty, like in SimNet
|
||||
func ForAllNets(t *testing.T, skipPow bool, testFunc func(*testing.T, *consensus.Config)) {
|
||||
func ForAllNets(t *testing.T, skipPow bool, testFunc func(*testing.T, *dagconfig.Params)) {
|
||||
allParams := []dagconfig.Params{
|
||||
dagconfig.MainnetParams,
|
||||
dagconfig.TestnetParams,
|
||||
@@ -18,12 +17,12 @@ func ForAllNets(t *testing.T, skipPow bool, testFunc func(*testing.T, *consensus
|
||||
}
|
||||
|
||||
for _, params := range allParams {
|
||||
consensusConfig := consensus.Config{Params: params}
|
||||
t.Run(consensusConfig.Name, func(t *testing.T) {
|
||||
paramsCopy := params
|
||||
t.Run(paramsCopy.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
consensusConfig.SkipProofOfWork = skipPow
|
||||
t.Logf("Running test for %s", consensusConfig.Name)
|
||||
testFunc(t, &consensusConfig)
|
||||
paramsCopy.SkipProofOfWork = skipPow
|
||||
t.Logf("Running test for %s", paramsCopy.Name)
|
||||
testFunc(t, ¶msCopy)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
)
|
||||
|
||||
@@ -34,6 +34,23 @@ func checkIntersectionWithRule(collection1 utxoCollection, collection2 utxoColle
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// minInt returns the smaller of x or y integer values
|
||||
func minInt(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// intersectionWithRemainderHavingDAAScore calculates an intersection between two utxoCollections
|
||||
// having same DAA score, returns the result and the remainder from collection1
|
||||
func intersectionWithRemainderHavingDAAScore(collection1, collection2 utxoCollection) (result, remainder utxoCollection) {
|
||||
result = make(utxoCollection, minInt(len(collection1), len(collection2)))
|
||||
remainder = make(utxoCollection, len(collection1))
|
||||
intersectionWithRemainderHavingDAAScoreInPlace(collection1, collection2, result, remainder)
|
||||
return
|
||||
}
|
||||
|
||||
// intersectionWithRemainderHavingDAAScoreInPlace calculates an intersection between two utxoCollections
|
||||
// having same DAA score, puts it into result and into remainder from collection1
|
||||
func intersectionWithRemainderHavingDAAScoreInPlace(collection1, collection2, result, remainder utxoCollection) {
|
||||
@@ -46,6 +63,15 @@ func intersectionWithRemainderHavingDAAScoreInPlace(collection1, collection2, re
|
||||
}
|
||||
}
|
||||
|
||||
// subtractionHavingDAAScore calculates a subtraction between collection1 and collection2
|
||||
// having same DAA score, returns the result
|
||||
func subtractionHavingDAAScore(collection1, collection2 utxoCollection) (result utxoCollection) {
|
||||
result = make(utxoCollection, len(collection1))
|
||||
|
||||
subtractionHavingDAAScoreInPlace(collection1, collection2, result)
|
||||
return
|
||||
}
|
||||
|
||||
// subtractionHavingDAAScoreInPlace calculates a subtraction between collection1 and collection2
|
||||
// having same DAA score, puts it into result
|
||||
func subtractionHavingDAAScoreInPlace(collection1, collection2, result utxoCollection) {
|
||||
@@ -56,6 +82,16 @@ func subtractionHavingDAAScoreInPlace(collection1, collection2, result utxoColle
|
||||
}
|
||||
}
|
||||
|
||||
// subtractionWithRemainderHavingDAAScore calculates a subtraction between collection1 and collection2
|
||||
// having same DAA score, returns the result and the remainder from collection1
|
||||
func subtractionWithRemainderHavingDAAScore(collection1, collection2 utxoCollection) (result, remainder utxoCollection) {
|
||||
result = make(utxoCollection, len(collection1))
|
||||
remainder = make(utxoCollection, len(collection1))
|
||||
|
||||
subtractionWithRemainderHavingDAAScoreInPlace(collection1, collection2, result, remainder)
|
||||
return
|
||||
}
|
||||
|
||||
// subtractionWithRemainderHavingDAAScoreInPlace calculates a subtraction between collection1 and collection2
|
||||
// having same DAA score, puts it into result and into remainder from collection1
|
||||
func subtractionWithRemainderHavingDAAScoreInPlace(collection1, collection2, result, remainder utxoCollection) {
|
||||
@@ -139,13 +175,13 @@ func diffFrom(this, other *mutableUTXODiff) (*mutableUTXODiff, error) {
|
||||
}
|
||||
|
||||
result := &mutableUTXODiff{
|
||||
toAdd: make(utxoCollection),
|
||||
toRemove: make(utxoCollection),
|
||||
toAdd: make(utxoCollection, len(this.toRemove)+len(other.toAdd)),
|
||||
toRemove: make(utxoCollection, len(this.toAdd)+len(other.toRemove)),
|
||||
}
|
||||
|
||||
// All transactions in this.toAdd:
|
||||
// If they are not in other.toAdd - should be added in result.toRemove
|
||||
inBothToAdd := make(utxoCollection)
|
||||
inBothToAdd := make(utxoCollection, len(this.toAdd))
|
||||
subtractionWithRemainderHavingDAAScoreInPlace(this.toAdd, other.toAdd, result.toRemove, inBothToAdd)
|
||||
// If they are in other.toRemove - base utxoSet is not the same
|
||||
if checkIntersection(inBothToAdd, this.toRemove) != checkIntersection(inBothToAdd, other.toRemove) {
|
||||
@@ -187,13 +223,13 @@ func withDiffInPlace(this *mutableUTXODiff, other *mutableUTXODiff) error {
|
||||
"withDiffInPlace: outpoint %s both in this.toAdd and in other.toAdd", offendingOutpoint)
|
||||
}
|
||||
|
||||
intersection := make(utxoCollection)
|
||||
intersection := make(utxoCollection, minInt(len(other.toRemove), len(this.toAdd)))
|
||||
// If not exists neither in toAdd nor in toRemove - add to toRemove
|
||||
intersectionWithRemainderHavingDAAScoreInPlace(other.toRemove, this.toAdd, intersection, this.toRemove)
|
||||
// If already exists in toAdd with the same DAA score - remove from toAdd
|
||||
this.toAdd.removeMultiple(intersection)
|
||||
|
||||
intersection = make(utxoCollection)
|
||||
intersection = make(utxoCollection, minInt(len(other.toAdd), len(this.toRemove)))
|
||||
// If not exists neither in toAdd nor in toRemove, or exists in toRemove with different DAA score - add to toAdd
|
||||
intersectionWithRemainderHavingDAAScoreInPlace(other.toAdd, this.toRemove, intersection, this.toAdd)
|
||||
// If already exists in toRemove with the same DAA score - remove from toRemove
|
||||
|
||||
@@ -13,7 +13,7 @@ type immutableUTXODiff struct {
|
||||
|
||||
func (iud *immutableUTXODiff) ToAdd() externalapi.UTXOCollection {
|
||||
if iud.isInvalidated {
|
||||
panic(errors.New("Attempt to read from an invalidated UTXODiff"))
|
||||
panic("Attempt to read from an invalidated UTXODiff")
|
||||
}
|
||||
|
||||
return iud.mutableUTXODiff.ToAdd()
|
||||
@@ -21,7 +21,7 @@ func (iud *immutableUTXODiff) ToAdd() externalapi.UTXOCollection {
|
||||
|
||||
func (iud *immutableUTXODiff) ToRemove() externalapi.UTXOCollection {
|
||||
if iud.isInvalidated {
|
||||
panic(errors.New("Attempt to read from an invalidated UTXODiff"))
|
||||
panic("Attempt to read from an invalidated UTXODiff")
|
||||
}
|
||||
|
||||
return iud.mutableUTXODiff.ToRemove()
|
||||
@@ -29,7 +29,7 @@ func (iud *immutableUTXODiff) ToRemove() externalapi.UTXOCollection {
|
||||
|
||||
func (iud *immutableUTXODiff) WithDiff(other externalapi.UTXODiff) (externalapi.UTXODiff, error) {
|
||||
if iud.isInvalidated {
|
||||
panic(errors.New("Attempt to read from an invalidated UTXODiff"))
|
||||
panic("Attempt to read from an invalidated UTXODiff")
|
||||
}
|
||||
|
||||
return iud.mutableUTXODiff.WithDiff(other)
|
||||
@@ -37,7 +37,7 @@ func (iud *immutableUTXODiff) WithDiff(other externalapi.UTXODiff) (externalapi.
|
||||
|
||||
func (iud *immutableUTXODiff) DiffFrom(other externalapi.UTXODiff) (externalapi.UTXODiff, error) {
|
||||
if iud.isInvalidated {
|
||||
panic(errors.New("Attempt to read from an invalidated UTXODiff"))
|
||||
panic("Attempt to read from an invalidated UTXODiff")
|
||||
}
|
||||
|
||||
return iud.mutableUTXODiff.DiffFrom(other)
|
||||
@@ -74,22 +74,9 @@ func NewUTXODiffFromCollections(toAdd, toRemove externalapi.UTXOCollection) (ext
|
||||
}
|
||||
|
||||
func (iud *immutableUTXODiff) CloneMutable() externalapi.MutableUTXODiff {
|
||||
if iud.isInvalidated {
|
||||
panic(errors.New("Attempt to read from an invalidated UTXODiff"))
|
||||
}
|
||||
return iud.cloneMutable()
|
||||
}
|
||||
|
||||
func (iud *immutableUTXODiff) Reversed() externalapi.UTXODiff {
|
||||
if iud.isInvalidated {
|
||||
panic(errors.New("Attempt to read from an invalidated UTXODiff"))
|
||||
}
|
||||
return &immutableUTXODiff{
|
||||
mutableUTXODiff: iud.mutableUTXODiff.Reversed(),
|
||||
isInvalidated: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (iud *immutableUTXODiff) cloneMutable() *mutableUTXODiff {
|
||||
if iud == nil {
|
||||
return nil
|
||||
@@ -97,7 +84,3 @@ func (iud *immutableUTXODiff) cloneMutable() *mutableUTXODiff {
|
||||
|
||||
return iud.mutableUTXODiff.clone()
|
||||
}
|
||||
|
||||
func (iud immutableUTXODiff) String() string {
|
||||
return iud.mutableUTXODiff.String()
|
||||
}
|
||||
|
||||
@@ -157,11 +157,3 @@ func (mud *mutableUTXODiff) clone() *mutableUTXODiff {
|
||||
func (mud *mutableUTXODiff) String() string {
|
||||
return fmt.Sprintf("toAdd: %s; toRemove: %s", mud.toAdd, mud.toRemove)
|
||||
}
|
||||
|
||||
func (mud *mutableUTXODiff) Reversed() *mutableUTXODiff {
|
||||
return &mutableUTXODiff{
|
||||
toAdd: mud.toRemove,
|
||||
toRemove: mud.toAdd,
|
||||
immutableReferences: mud.immutableReferences,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,10 +177,10 @@ var testnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0,
|
||||
// testnetGenesisHash is the hash of the first block in the block DAG for the test
|
||||
// network (genesis block).
|
||||
var testnetGenesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
|
||||
0xac, 0x23, 0xff, 0xc3, 0x85, 0xd3, 0x88, 0x99,
|
||||
0xfd, 0xb8, 0x83, 0x30, 0x80, 0x3a, 0x3d, 0xbf,
|
||||
0xf7, 0x9b, 0x96, 0x9e, 0x4c, 0xd5, 0x1b, 0xf0,
|
||||
0x0e, 0x77, 0xb6, 0x87, 0x70, 0xaa, 0x4e, 0x1f,
|
||||
0x8f, 0x83, 0xf5, 0x33, 0x77, 0xa4, 0x80, 0xa7,
|
||||
0x93, 0xf3, 0x17, 0xee, 0x3e, 0x8f, 0xf5, 0xaf,
|
||||
0x16, 0x6d, 0x87, 0x1d, 0x54, 0xfd, 0xe7, 0x79,
|
||||
0xa2, 0xab, 0x6f, 0xc3, 0x76, 0x60, 0xc3, 0x64,
|
||||
})
|
||||
|
||||
// testnetGenesisMerkleRoot is the hash of the first transaction in the genesis block
|
||||
@@ -201,9 +201,9 @@ var testnetGenesisBlock = externalapi.DomainBlock{
|
||||
testnetGenesisMerkleRoot,
|
||||
&externalapi.DomainHash{},
|
||||
externalapi.NewDomainHashFromByteArray(muhash.EmptyMuHashHash.AsArray()),
|
||||
0x178547bee50,
|
||||
0x177bfd44a10,
|
||||
0x1e7fffff,
|
||||
0x2de70,
|
||||
0x64d74,
|
||||
),
|
||||
Transactions: []*externalapi.DomainTransaction{testnetGenesisCoinbaseTx},
|
||||
}
|
||||
|
||||
@@ -256,11 +256,11 @@ var MainnetParams = Params{
|
||||
// TestnetParams defines the network parameters for the test Kaspa network.
|
||||
var TestnetParams = Params{
|
||||
K: defaultGHOSTDAGK,
|
||||
Name: "kaspa-testnet-5",
|
||||
Name: "kaspa-testnet-2",
|
||||
Net: appmessage.Testnet,
|
||||
RPCPort: "16210",
|
||||
DefaultPort: "16211",
|
||||
DNSSeeds: []string{"testnet-5-dnsseed.daglabs-dev.com"},
|
||||
DNSSeeds: []string{"testnet-2-dnsseed.daglabs-dev.com"},
|
||||
|
||||
// DAG parameters
|
||||
GenesisBlock: &testnetGenesisBlock,
|
||||
|
||||
@@ -3,6 +3,7 @@ package domain
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager"
|
||||
infrastructuredatabase "github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||
)
|
||||
@@ -27,15 +28,15 @@ func (d domain) MiningManager() miningmanager.MiningManager {
|
||||
}
|
||||
|
||||
// New instantiates a new instance of a Domain object
|
||||
func New(consensusConfig *consensus.Config, db infrastructuredatabase.Database) (Domain, error) {
|
||||
func New(dagParams *dagconfig.Params, db infrastructuredatabase.Database, isArchivalNode bool) (Domain, error) {
|
||||
consensusFactory := consensus.NewFactory()
|
||||
consensusInstance, err := consensusFactory.NewConsensus(consensusConfig, db)
|
||||
consensusInstance, err := consensusFactory.NewConsensus(dagParams, db, isArchivalNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
miningManagerFactory := miningmanager.NewFactory()
|
||||
miningManager := miningManagerFactory.NewMiningManager(consensusInstance, &consensusConfig.Params)
|
||||
miningManager := miningManagerFactory.NewMiningManager(consensusInstance, dagParams)
|
||||
|
||||
return &domain{
|
||||
consensus: consensusInstance,
|
||||
|
||||
@@ -1,38 +1,41 @@
|
||||
package miningmanager_test
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager"
|
||||
"github.com/pkg/errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
"github.com/kaspanet/kaspad/domain/miningmanager"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
const blockMaxMass uint64 = 10000000
|
||||
|
||||
// TestValidateAndInsertTransaction verifies that valid transactions were successfully inserted into the mempool.
|
||||
func TestValidateAndInsertTransaction(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
params.BlockCoinbaseMaturity = 0
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestValidateAndInsertTransaction")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestValidateAndInsertTransaction")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up TestConsensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params)
|
||||
miningManager := miningFactory.NewMiningManager(tc, params)
|
||||
transactionsToInsert := make([]*externalapi.DomainTransaction, 10)
|
||||
for i := range transactionsToInsert {
|
||||
transactionsToInsert[i] = createTransactionWithUTXOEntry(t, i)
|
||||
@@ -55,7 +58,7 @@ func TestValidateAndInsertTransaction(t *testing.T) {
|
||||
|
||||
// The parent's transaction was inserted by consensus(AddBlock), and we want to verify that
|
||||
// the transaction is not considered an orphan and inserted into the mempool.
|
||||
transactionNotAnOrphan, err := createChildTxWhenParentTxWasAddedByConsensus(consensusConfig, tc)
|
||||
transactionNotAnOrphan, err := createChildTxWhenParentTxWasAddedByConsensus(params, tc)
|
||||
if err != nil {
|
||||
t.Fatalf("Error in createParentAndChildrenTransaction: %v", err)
|
||||
}
|
||||
@@ -73,17 +76,17 @@ func TestValidateAndInsertTransaction(t *testing.T) {
|
||||
// TestInsertDoubleTransactionsToMempool verifies that an attempt to insert a transaction
|
||||
// more than once into the mempool will result in raising an appropriate error.
|
||||
func TestInsertDoubleTransactionsToMempool(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestInsertDoubleTransactionsToMempool")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestInsertDoubleTransactionsToMempool")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up TestConsensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params)
|
||||
miningManager := miningFactory.NewMiningManager(tc, params)
|
||||
transaction := createTransactionWithUTXOEntry(t, 0)
|
||||
err = miningManager.ValidateAndInsertTransaction(transaction, true)
|
||||
if err != nil {
|
||||
@@ -98,17 +101,17 @@ func TestInsertDoubleTransactionsToMempool(t *testing.T) {
|
||||
|
||||
// TestHandleNewBlockTransactions verifies that all the transactions in the block were successfully removed from the mempool.
|
||||
func TestHandleNewBlockTransactions(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestHandleNewBlockTransactions")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestHandleNewBlockTransactions")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up TestConsensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params)
|
||||
miningManager := miningFactory.NewMiningManager(tc, params)
|
||||
transactionsToInsert := make([]*externalapi.DomainTransaction, 10)
|
||||
for i := range transactionsToInsert {
|
||||
transaction := createTransactionWithUTXOEntry(t, i)
|
||||
@@ -164,17 +167,17 @@ func domainBlocksToBlockIds(blocks []*externalapi.DomainTransaction) []*external
|
||||
// TestDoubleSpends verifies that any transactions which are now double spends as a result of the block's new transactions
|
||||
// will be removed from the mempool.
|
||||
func TestDoubleSpends(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestDoubleSpends")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestDoubleSpends")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed setting up TestConsensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params)
|
||||
miningManager := miningFactory.NewMiningManager(tc, params)
|
||||
transactionInTheMempool := createTransactionWithUTXOEntry(t, 0)
|
||||
err = miningManager.ValidateAndInsertTransaction(transactionInTheMempool, true)
|
||||
if err != nil {
|
||||
@@ -196,18 +199,18 @@ func TestDoubleSpends(t *testing.T) {
|
||||
|
||||
// TestOrphanTransactions verifies that a transaction could be a part of a new block template, only if it's not an orphan.
|
||||
func TestOrphanTransactions(t *testing.T) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||
|
||||
consensusConfig.BlockCoinbaseMaturity = 0
|
||||
params.BlockCoinbaseMaturity = 0
|
||||
factory := consensus.NewFactory()
|
||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestOrphanTransactions")
|
||||
tc, teardown, err := factory.NewTestConsensus(params, false, "TestOrphanTransactions")
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting up TestConsensus: %+v", err)
|
||||
}
|
||||
defer teardown(false)
|
||||
|
||||
miningFactory := miningmanager.NewFactory()
|
||||
miningManager := miningFactory.NewMiningManager(tc, &consensusConfig.Params)
|
||||
miningManager := miningFactory.NewMiningManager(tc, params)
|
||||
// Before each parent transaction, We will add two blocks by consensus in order to fund the parent transactions.
|
||||
parentTransactions, childTransactions, err := createArraysOfParentAndChildrenTransactions(tc)
|
||||
if err != nil {
|
||||
@@ -383,8 +386,9 @@ func createParentAndChildrenTransactions(tc testapi.TestConsensus) (*externalapi
|
||||
return txParent, txChild, nil
|
||||
}
|
||||
|
||||
func createChildTxWhenParentTxWasAddedByConsensus(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainTransaction, error) {
|
||||
firstBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||
func createChildTxWhenParentTxWasAddedByConsensus(params *dagconfig.Params, tc testapi.TestConsensus) (*externalapi.DomainTransaction, error) {
|
||||
|
||||
firstBlockHash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "AddBlock: %v", err)
|
||||
}
|
||||
|
||||
@@ -76,52 +76,51 @@ var RunServiceCommand func(string) error
|
||||
//
|
||||
// See loadConfig for details on the configuration load process.
|
||||
type Flags struct {
|
||||
ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"`
|
||||
ConfigFile string `short:"C" long:"configfile" description:"Path to configuration file"`
|
||||
AppDir string `short:"b" long:"appdir" description:"Directory to store data"`
|
||||
LogDir string `long:"logdir" description:"Directory to log output."`
|
||||
AddPeers []string `short:"a" long:"addpeer" description:"Add a peer to connect with at startup"`
|
||||
ConnectPeers []string `long:"connect" description:"Connect only to the specified peers at startup"`
|
||||
DisableListen bool `long:"nolisten" description:"Disable listening for incoming connections -- NOTE: Listening is automatically disabled if the --connect or --proxy options are used without also specifying listen interfaces via --listen"`
|
||||
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"`
|
||||
MaxInboundPeers int `long:"maxinpeers" description:"Max number of inbound peers"`
|
||||
DisableBanning bool `long:"nobanning" description:"Disable 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"`
|
||||
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)"`
|
||||
RPCListeners []string `long:"rpclisten" description:"Add an interface/port to listen for RPC connections (default port: 16110, testnet: 16210)"`
|
||||
RPCCert string `long:"rpccert" description:"File containing the certificate file"`
|
||||
RPCKey string `long:"rpckey" description:"File containing the certificate key"`
|
||||
RPCMaxClients int `long:"rpcmaxclients" description:"Max number of RPC clients for standard connections"`
|
||||
RPCMaxWebsockets int `long:"rpcmaxwebsockets" description:"Max number of RPC websocket connections"`
|
||||
RPCMaxConcurrentReqs int `long:"rpcmaxconcurrentreqs" description:"Max number of concurrent RPC requests that may be processed concurrently"`
|
||||
DisableRPC bool `long:"norpc" description:"Disable built-in RPC server"`
|
||||
DisableDNSSeed bool `long:"nodnsseed" description:"Disable DNS seeding for peers"`
|
||||
DNSSeed string `long:"dnsseed" description:"Override DNS seeds with specified hostname (Only 1 hostname allowed)"`
|
||||
GRPCSeed string `long:"grpcseed" description:"Hostname of gRPC server for seeding peers"`
|
||||
ExternalIPs []string `long:"externalip" description:"Add an ip to the list of local addresses we claim to listen on to peers"`
|
||||
Proxy string `long:"proxy" description:"Connect via SOCKS5 proxy (eg. 127.0.0.1:9050)"`
|
||||
ProxyUser string `long:"proxyuser" description:"Username for proxy server"`
|
||||
ProxyPass string `long:"proxypass" default-mask:"-" description:"Password for proxy server"`
|
||||
DbType string `long:"dbtype" description:"Database backend to use for the Block DAG"`
|
||||
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
|
||||
LogLevel string `short:"d" long:"loglevel" description:"Logging level for all subsystems {trace, debug, info, warn, error, critical} -- You may also specify <subsystem>=<level>,<subsystem2>=<level>,... to set the log level for individual subsystems -- Use show to list available subsystems"`
|
||||
Upnp bool `long:"upnp" description:"Use UPnP to map our listening port outside of NAT"`
|
||||
MinRelayTxFee float64 `long:"minrelaytxfee" description:"The minimum transaction fee in KAS/kB to be considered a non-zero fee."`
|
||||
MaxOrphanTxs int `long:"maxorphantx" description:"Max number of orphan transactions to keep in memory"`
|
||||
BlockMaxMass uint64 `long:"blockmaxmass" description:"Maximum transaction mass to be used when creating a block"`
|
||||
UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."`
|
||||
NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"`
|
||||
SigCacheMaxSize uint `long:"sigcachemaxsize" description:"The maximum number of entries in the signature verification cache"`
|
||||
BlocksOnly bool `long:"blocksonly" description:"Do not accept transactions from remote peers."`
|
||||
RelayNonStd bool `long:"relaynonstd" description:"Relay non-standard transactions regardless of the default settings for the active network."`
|
||||
RejectNonStd bool `long:"rejectnonstd" description:"Reject non-standard transactions regardless of the default settings for the active network."`
|
||||
ResetDatabase bool `long:"reset-db" description:"Reset database before starting node. It's needed when switching between subnetworks."`
|
||||
MaxUTXOCacheSize uint64 `long:"maxutxocachesize" description:"Max size of loaded UTXO into ram from the disk in bytes"`
|
||||
UTXOIndex bool `long:"utxoindex" description:"Enable the UTXO index"`
|
||||
IsArchivalNode bool `long:"archival" description:"Run as an archival node: don't delete old block data when moving the pruning point (Warning: heavy disk usage)'"`
|
||||
EnableSanityCheckPruningUTXOSet bool `long:"enable-sanity-check-pruning-utxo" hidden:"true" description:"When moving the pruning point - check that the utxo set matches the utxo commitment"`
|
||||
ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"`
|
||||
ConfigFile string `short:"C" long:"configfile" description:"Path to configuration file"`
|
||||
AppDir string `short:"b" long:"appdir" description:"Directory to store data"`
|
||||
LogDir string `long:"logdir" description:"Directory to log output."`
|
||||
AddPeers []string `short:"a" long:"addpeer" description:"Add a peer to connect with at startup"`
|
||||
ConnectPeers []string `long:"connect" description:"Connect only to the specified peers at startup"`
|
||||
DisableListen bool `long:"nolisten" description:"Disable listening for incoming connections -- NOTE: Listening is automatically disabled if the --connect or --proxy options are used without also specifying listen interfaces via --listen"`
|
||||
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"`
|
||||
MaxInboundPeers int `long:"maxinpeers" description:"Max number of inbound peers"`
|
||||
DisableBanning bool `long:"nobanning" description:"Disable 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"`
|
||||
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)"`
|
||||
RPCListeners []string `long:"rpclisten" description:"Add an interface/port to listen for RPC connections (default port: 16110, testnet: 16210)"`
|
||||
RPCCert string `long:"rpccert" description:"File containing the certificate file"`
|
||||
RPCKey string `long:"rpckey" description:"File containing the certificate key"`
|
||||
RPCMaxClients int `long:"rpcmaxclients" description:"Max number of RPC clients for standard connections"`
|
||||
RPCMaxWebsockets int `long:"rpcmaxwebsockets" description:"Max number of RPC websocket connections"`
|
||||
RPCMaxConcurrentReqs int `long:"rpcmaxconcurrentreqs" description:"Max number of concurrent RPC requests that may be processed concurrently"`
|
||||
DisableRPC bool `long:"norpc" description:"Disable built-in RPC server"`
|
||||
DisableDNSSeed bool `long:"nodnsseed" description:"Disable DNS seeding for peers"`
|
||||
DNSSeed string `long:"dnsseed" description:"Override DNS seeds with specified hostname (Only 1 hostname allowed)"`
|
||||
GRPCSeed string `long:"grpcseed" description:"Hostname of gRPC server for seeding peers"`
|
||||
ExternalIPs []string `long:"externalip" description:"Add an ip to the list of local addresses we claim to listen on to peers"`
|
||||
Proxy string `long:"proxy" description:"Connect via SOCKS5 proxy (eg. 127.0.0.1:9050)"`
|
||||
ProxyUser string `long:"proxyuser" description:"Username for proxy server"`
|
||||
ProxyPass string `long:"proxypass" default-mask:"-" description:"Password for proxy server"`
|
||||
DbType string `long:"dbtype" description:"Database backend to use for the Block DAG"`
|
||||
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
|
||||
LogLevel string `short:"d" long:"loglevel" description:"Logging level for all subsystems {trace, debug, info, warn, error, critical} -- You may also specify <subsystem>=<level>,<subsystem2>=<level>,... to set the log level for individual subsystems -- Use show to list available subsystems"`
|
||||
Upnp bool `long:"upnp" description:"Use UPnP to map our listening port outside of NAT"`
|
||||
MinRelayTxFee float64 `long:"minrelaytxfee" description:"The minimum transaction fee in KAS/kB to be considered a non-zero fee."`
|
||||
MaxOrphanTxs int `long:"maxorphantx" description:"Max number of orphan transactions to keep in memory"`
|
||||
BlockMaxMass uint64 `long:"blockmaxmass" description:"Maximum transaction mass to be used when creating a block"`
|
||||
UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."`
|
||||
NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"`
|
||||
SigCacheMaxSize uint `long:"sigcachemaxsize" description:"The maximum number of entries in the signature verification cache"`
|
||||
BlocksOnly bool `long:"blocksonly" description:"Do not accept transactions from remote peers."`
|
||||
RelayNonStd bool `long:"relaynonstd" description:"Relay non-standard transactions regardless of the default settings for the active network."`
|
||||
RejectNonStd bool `long:"rejectnonstd" description:"Reject non-standard transactions regardless of the default settings for the active network."`
|
||||
ResetDatabase bool `long:"reset-db" description:"Reset database before starting node. It's needed when switching between subnetworks."`
|
||||
MaxUTXOCacheSize uint64 `long:"maxutxocachesize" description:"Max size of loaded UTXO into ram from the disk in bytes"`
|
||||
UTXOIndex bool `long:"utxoindex" description:"Enable the UTXO index"`
|
||||
IsArchivalNode bool `long:"archival" description:"Run as an archival node: don't delete old block data when moving the pruning point (Warning: heavy disk usage)'"`
|
||||
NetworkFlags
|
||||
ServiceOptions *ServiceOptions
|
||||
}
|
||||
@@ -577,6 +576,7 @@ func LoadConfig() (*Config, error) {
|
||||
if configFileError != nil {
|
||||
log.Warnf("%s", configFileError)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
package addressmanager
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/database/ldb"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/database/ldb"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
)
|
||||
|
||||
func newAddressManagerForTest(t *testing.T, testName string) (addressManager *AddressManager, teardown func()) {
|
||||
@@ -274,7 +274,6 @@ func TestRestoreAddressManager(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Could not create a database: %s", err)
|
||||
}
|
||||
defer database.Close()
|
||||
|
||||
// Recreate an addressManager with a the previous database
|
||||
addressManager, err = New(NewConfig(cfg), database)
|
||||
|
||||
@@ -113,7 +113,6 @@ func (x *RpcBlock) fromAppMessage(message *appmessage.RPCBlock) error {
|
||||
*x = RpcBlock{
|
||||
Header: header,
|
||||
Transactions: transactions,
|
||||
VerboseData: verboseData,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package rpcclient
|
||||
|
||||
import "github.com/kaspanet/kaspad/app/appmessage"
|
||||
|
||||
// GetInfo sends an RPC request respective to the function's name and returns the RPC server's response
|
||||
func (c *RPCClient) GetInfo() (*appmessage.GetInfoResponseMessage, error) {
|
||||
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewGetInfoRequestMessage())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := c.route(appmessage.CmdGetInfoResponseMessage).DequeueWithTimeout(c.timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
getInfoResponse := response.(*appmessage.GetInfoResponseMessage)
|
||||
if getInfoResponse.Error != nil {
|
||||
return nil, c.convertRPCError(getInfoResponse.Error)
|
||||
}
|
||||
return getInfoResponse, nil
|
||||
}
|
||||
@@ -114,6 +114,6 @@ func (s *Service) logServiceStart() {
|
||||
var message string
|
||||
message += fmt.Sprintf("%s version %s\n", s.description.DisplayName, version.Version())
|
||||
message += fmt.Sprintf("Configuration file: %s\n", s.cfg.ConfigFile)
|
||||
message += fmt.Sprintf("Application directory: %s\n", s.cfg.AppDir)
|
||||
message += fmt.Sprintf("Data directory: %s\n", s.cfg.DataDir)
|
||||
message += fmt.Sprintf("Logs directory: %s\n", s.cfg.LogDir)
|
||||
}
|
||||
|
||||
@@ -12,22 +12,23 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/mining"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/stability-tests/common/rpc"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// FromFile mines all blocks as described by `jsonFile`
|
||||
func FromFile(jsonFile string, consensusConfig *consensus.Config, rpcClient *rpc.Client, dataDir string) error {
|
||||
func FromFile(jsonFile string, dagParams *dagconfig.Params, rpcClient *rpc.Client, dataDir string) error {
|
||||
log.Infof("Mining blocks from JSON file %s from data directory %s", jsonFile, dataDir)
|
||||
blockChan, err := readBlocks(jsonFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return mineBlocks(consensusConfig, rpcClient, blockChan, dataDir)
|
||||
return mineBlocks(dagParams, rpcClient, blockChan, dataDir)
|
||||
}
|
||||
|
||||
func mineBlocks(consensusConfig *consensus.Config, rpcClient *rpc.Client, blockChan <-chan JSONBlock, dataDir string) error {
|
||||
func mineBlocks(dagParams *dagconfig.Params, rpcClient *rpc.Client, blockChan <-chan JSONBlock, dataDir string) error {
|
||||
mdb, err := newMiningDB(dataDir)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -36,7 +37,7 @@ func mineBlocks(consensusConfig *consensus.Config, rpcClient *rpc.Client, blockC
|
||||
dbPath := filepath.Join(dataDir, "db")
|
||||
factory := consensus.NewFactory()
|
||||
factory.SetTestDataDir(dbPath)
|
||||
testConsensus, tearDownFunc, err := factory.NewTestConsensus(consensusConfig, "minejson")
|
||||
testConsensus, tearDownFunc, err := factory.NewTestConsensus(dagParams, false, "minejson")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -49,7 +50,7 @@ func mineBlocks(consensusConfig *consensus.Config, rpcClient *rpc.Client, blockC
|
||||
|
||||
log.Infof("Starting with data directory with %d headers and %d blocks", info.HeaderCount, info.BlockCount)
|
||||
|
||||
err = mdb.putID("0", consensusConfig.GenesisHash)
|
||||
err = mdb.putID("0", dagParams.GenesisHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,29 +1,26 @@
|
||||
ARG KASPAD_IMAGE
|
||||
ARG KASPAMINER_IMAGE
|
||||
ARG KASPAD_VERSION
|
||||
|
||||
FROM ${KASPAD_IMAGE} as kaspad
|
||||
FROM ${KASPAMINER_IMAGE} as kaspaminer
|
||||
FROM 578712463641.dkr.ecr.eu-central-1.amazonaws.com/kaspad-release-candidate:$KASPAD_VERSION as kaspad
|
||||
FROM 578712463641.dkr.ecr.eu-central-1.amazonaws.com/kaspaminer-release-candidate:$KASPAD_VERSION as kaspaminer
|
||||
|
||||
FROM golang:1.16-alpine
|
||||
|
||||
RUN mkdir -p /go/src/github.com/kaspanet/kaspad
|
||||
|
||||
WORKDIR /go/src/github.com/kaspanet/kaspad
|
||||
|
||||
RUN apk add bash build-base git
|
||||
|
||||
COPY go.mod .
|
||||
COPY go.sum .
|
||||
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
ARG KASPAD_VERSION
|
||||
|
||||
COPY --from=kaspad /app/ /app/
|
||||
COPY --from=kaspaminer /app/ /app/
|
||||
ENV PATH="/app:${PATH}"
|
||||
|
||||
WORKDIR /go/src/github.com/kaspanet/kaspad/stability-tests
|
||||
COPY . /tests
|
||||
|
||||
WORKDIR /tests
|
||||
|
||||
RUN git ls-remote https://github.com/kaspanet/kaspad.git $KASPAD_VERSION | awk '{print $1;}' > /tmp/kaspad_git_commit
|
||||
RUN go mod edit -dropreplace github.com/kaspanet/kaspad
|
||||
RUN go mod edit -replace github.com/kaspanet/kaspad=github.com/kaspanet/kaspad@`cat /tmp/kaspad_git_commit` ;
|
||||
RUN go mod download
|
||||
|
||||
RUN go install ./...
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# Mempool Limits tool
|
||||
|
||||
This tool:
|
||||
|
||||
1. Fills up the mempool beyond its transaction limit to make sure eviction works correctly
|
||||
2. Mines blocks until the mempool is expected to become empty
|
||||
|
||||
## Running
|
||||
|
||||
1. `go install` kaspad and mempool-limits.
|
||||
2. `cd run`
|
||||
3. `./run.sh`
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package mempoollimits
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/jessevdk/go-flags"
|
||||
"github.com/kaspanet/kaspad/stability-tests/common"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultLogFilename = "mempool-limits.log"
|
||||
defaultErrLogFilename = "mempool-limits_err.log"
|
||||
)
|
||||
|
||||
var (
|
||||
// Default configuration options
|
||||
defaultLogFile = filepath.Join(common.DefaultAppDir, defaultLogFilename)
|
||||
defaultErrLogFile = filepath.Join(common.DefaultAppDir, defaultErrLogFilename)
|
||||
)
|
||||
|
||||
type configFlags struct {
|
||||
LogLevel string `long:"loglevel" description:"Set log level {trace, debug, info, warn, error, critical}"`
|
||||
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
|
||||
KaspadRPCAddress string `long:"rpc-address" description:"RPC address of the kaspad node"`
|
||||
}
|
||||
|
||||
var cfg *configFlags
|
||||
|
||||
func activeConfig() *configFlags {
|
||||
return cfg
|
||||
}
|
||||
|
||||
func parseConfig() error {
|
||||
cfg = &configFlags{}
|
||||
parser := flags.NewParser(cfg, flags.PrintErrors|flags.HelpFlag|flags.IgnoreUnknown)
|
||||
_, err := parser.Parse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
initLog(defaultLogFile, defaultErrLogFile)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package mempoollimits
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/stability-tests/common"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
var (
|
||||
backendLog = logger.NewBackend()
|
||||
log = backendLog.Logger("MPLM")
|
||||
spawn = panics.GoroutineWrapperFunc(log)
|
||||
)
|
||||
|
||||
func initLog(logFile, errLogFile string) {
|
||||
level := logger.LevelInfo
|
||||
if activeConfig().LogLevel != "" {
|
||||
var ok bool
|
||||
level, ok = logger.LevelFromString(activeConfig().LogLevel)
|
||||
if !ok {
|
||||
fmt.Fprintf(os.Stderr, "Log level %s doesn't exists", activeConfig().LogLevel)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
log.SetLevel(level)
|
||||
common.InitBackend(backendLog, logFile, errLogFile)
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
package mempoollimits
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
|
||||
"github.com/kaspanet/kaspad/stability-tests/common"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
"github.com/kaspanet/kaspad/util/profiling"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
mempoolSizeLimit = 1_000_000
|
||||
overfillMempoolByAmount = 1_000
|
||||
)
|
||||
|
||||
func TestMempoolLimits(t *testing.T) {
|
||||
if os.Getenv("RUN_STABILITY_TESTS") == "" {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
defer panics.HandlePanic(log, "mempool-limits-main", nil)
|
||||
err := parseConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("error in parseConfig: %s", err)
|
||||
}
|
||||
defer backendLog.Close()
|
||||
common.UseLogger(backendLog, log.Level())
|
||||
|
||||
cfg := activeConfig()
|
||||
if cfg.Profile != "" {
|
||||
profiling.Start(cfg.Profile, log)
|
||||
}
|
||||
|
||||
payAddressKeyPair := decodePayAddressKeyPair(t)
|
||||
payToPayAddressScript := buildPayToPayAddressScript(t)
|
||||
rpcClient := buildRPCClient(t)
|
||||
|
||||
// Create enough funds for the test
|
||||
fundingTransactions := generateFundingCoinbaseTransactions(t, rpcClient)
|
||||
|
||||
// Fill up the mempool to the brim
|
||||
submitAnAmountOfTransactionsToTheMempool(t, rpcClient, payAddressKeyPair,
|
||||
payToPayAddressScript, fundingTransactions, mempoolSizeLimit, false)
|
||||
|
||||
// Make sure that the mempool size is exactly the limit
|
||||
mempoolSize := getMempoolSize(t, rpcClient)
|
||||
if mempoolSize != mempoolSizeLimit {
|
||||
t.Fatalf("Unexpected mempool size. Want: %d, got: %d",
|
||||
mempoolSizeLimit, mempoolSize)
|
||||
}
|
||||
|
||||
// Add some more transactions to the mempool. We expect the
|
||||
// mempool to either not grow or even to shrink, since an eviction
|
||||
// may also remove any dependant (chained) transactions.
|
||||
// Note that we pass ignoreOrphanRejects: true because we
|
||||
// expect some of the submitted transactions to depend on
|
||||
// transactions that had been evicted from the mempool
|
||||
submitAnAmountOfTransactionsToTheMempool(t, rpcClient, payAddressKeyPair,
|
||||
payToPayAddressScript, fundingTransactions, overfillMempoolByAmount, true)
|
||||
|
||||
// Make sure that the mempool size is the limit or smaller
|
||||
mempoolSize = getMempoolSize(t, rpcClient)
|
||||
if mempoolSize > mempoolSizeLimit {
|
||||
t.Fatalf("Unexpected mempool size. Want at most: %d, got: %d",
|
||||
mempoolSizeLimit, mempoolSize)
|
||||
}
|
||||
|
||||
// Empty mempool out by continuously adding blocks to the DAG
|
||||
emptyOutMempool(t, rpcClient)
|
||||
|
||||
log.Infof("mempool-limits passed")
|
||||
}
|
||||
|
||||
func buildRPCClient(t *testing.T) *rpcclient.RPCClient {
|
||||
client, err := rpcclient.NewRPCClient(activeConfig().KaspadRPCAddress)
|
||||
if err != nil {
|
||||
t.Fatalf("error connecting to %s: %s", activeConfig().KaspadRPCAddress, err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
func getMempoolSize(t *testing.T, rpcClient *rpcclient.RPCClient) uint64 {
|
||||
getInfoResponse, err := rpcClient.GetInfo()
|
||||
if err != nil {
|
||||
t.Fatalf("GetInfo: %+v", err)
|
||||
}
|
||||
return getInfoResponse.MempoolSize
|
||||
}
|
||||
|
||||
func emptyOutMempool(t *testing.T, rpcClient *rpcclient.RPCClient) {
|
||||
log.Infof("Adding blocks until mempool shrinks to 0 transactions")
|
||||
getInfoResponse, err := rpcClient.GetInfo()
|
||||
if err != nil {
|
||||
t.Fatalf("GetInfo: %+v", err)
|
||||
}
|
||||
currentMempoolSize := getInfoResponse.MempoolSize
|
||||
for currentMempoolSize > 0 {
|
||||
mineBlockAndGetCoinbaseTransaction(t, rpcClient)
|
||||
getInfoResponse, err := rpcClient.GetInfo()
|
||||
if err != nil {
|
||||
t.Fatalf("GetInfo: %+v", err)
|
||||
}
|
||||
if getInfoResponse.MempoolSize == currentMempoolSize {
|
||||
t.Fatalf("Mempool did not shrink after a block was added to the DAG")
|
||||
}
|
||||
log.Infof("Mempool shrank from %d transactions to %d transactions",
|
||||
currentMempoolSize, getInfoResponse.MempoolSize)
|
||||
currentMempoolSize = getInfoResponse.MempoolSize
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
APPDIR=/tmp/kaspad-temp
|
||||
KASPAD_RPC_PORT=29587
|
||||
|
||||
rm -rf "${APPDIR}"
|
||||
|
||||
kaspad --simnet --appdir="${APPDIR}" --rpclisten=0.0.0.0:"${KASPAD_RPC_PORT}" --profile=6061 &
|
||||
KASPAD_PID=$!
|
||||
|
||||
sleep 1
|
||||
|
||||
RUN_STABILITY_TESTS=true go test ../ -v -timeout 86400s -- --rpc-address=127.0.0.1:"${KASPAD_RPC_PORT}" --profile=7000
|
||||
TEST_EXIT_CODE=$?
|
||||
|
||||
kill $KASPAD_PID
|
||||
|
||||
wait $KASPAD_PID
|
||||
KASPAD_EXIT_CODE=$?
|
||||
|
||||
echo "Exit code: $TEST_EXIT_CODE"
|
||||
echo "Kaspad exit code: $KASPAD_EXIT_CODE"
|
||||
|
||||
if [ $TEST_EXIT_CODE -eq 0 ] && [ $KASPAD_EXIT_CODE -eq 0 ]; then
|
||||
echo "mempool-limits test: PASSED"
|
||||
exit 0
|
||||
fi
|
||||
echo "mempool-limits test: FAILED"
|
||||
exit 1
|
||||
@@ -1,200 +0,0 @@
|
||||
package mempoollimits
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"github.com/kaspanet/go-secp256k1"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||
utxopkg "github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
|
||||
"github.com/kaspanet/kaspad/stability-tests/common/mine"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
payAddress = "kaspasim:qzuax2jhawd354e54thhpd9m9wg03pdzwjlpr4vtq3k7xrpumhhtwa2hkr3ep"
|
||||
payAddressPrivateKey = "05d8f681e954a550395ee2297fc1a14f6e801f554c0b9d48cd7165a7ea72ff77"
|
||||
fundingCoinbaseTransactionAmount = 1000
|
||||
outputsPerTransaction = 3
|
||||
transactionFee = 1000
|
||||
coinbaseMaturity = 100
|
||||
)
|
||||
|
||||
// fundingCoinbaseTransactions contains a collection of transactions
|
||||
// to be utilized when generating further transactions to fill up
|
||||
// the mempool.
|
||||
// It's a separate type because we modify the transactions in place
|
||||
// whenever we pass an instance of this type into
|
||||
// submitAnAmountOfTransactionsToTheMempool.
|
||||
type fundingCoinbaseTransactions struct {
|
||||
transactions []*externalapi.DomainTransaction
|
||||
}
|
||||
|
||||
func generateFundingCoinbaseTransactions(t *testing.T, rpcClient *rpcclient.RPCClient) *fundingCoinbaseTransactions {
|
||||
// Mine a block, since we need at least one block above the genesis
|
||||
// to create a spendable UTXO
|
||||
mineBlockAndGetCoinbaseTransaction(t, rpcClient)
|
||||
|
||||
log.Infof("Generating funding coinbase transactions")
|
||||
fundingCoinbaseTransactions := &fundingCoinbaseTransactions{
|
||||
transactions: make([]*externalapi.DomainTransaction, fundingCoinbaseTransactionAmount),
|
||||
}
|
||||
for i := 0; i < fundingCoinbaseTransactionAmount; i++ {
|
||||
fundingCoinbaseTransactions.transactions[i] = mineBlockAndGetCoinbaseTransaction(t, rpcClient)
|
||||
}
|
||||
|
||||
log.Infof("Maturing funding coinbase transactions")
|
||||
for i := 0; i < coinbaseMaturity; i++ {
|
||||
mineBlockAndGetCoinbaseTransaction(t, rpcClient)
|
||||
}
|
||||
|
||||
return fundingCoinbaseTransactions
|
||||
}
|
||||
|
||||
func submitAnAmountOfTransactionsToTheMempool(t *testing.T, rpcClient *rpcclient.RPCClient,
|
||||
payAddressKeyPair *secp256k1.SchnorrKeyPair, payToPayAddressScript *externalapi.ScriptPublicKey,
|
||||
fundingTransactions *fundingCoinbaseTransactions, amountToSubmit int, ignoreOrphanRejects bool) {
|
||||
|
||||
log.Infof("Generating %d transactions", amountToSubmit)
|
||||
transactions := make([]*externalapi.DomainTransaction, 0)
|
||||
for len(transactions) < amountToSubmit {
|
||||
var coinbaseTransaction *externalapi.DomainTransaction
|
||||
coinbaseTransaction, fundingTransactions.transactions = fundingTransactions.transactions[0], fundingTransactions.transactions[1:]
|
||||
|
||||
unspentTransactions := []*externalapi.DomainTransaction{coinbaseTransaction}
|
||||
for len(transactions) < amountToSubmit && len(unspentTransactions) > 0 {
|
||||
var transactionToSpend *externalapi.DomainTransaction
|
||||
transactionToSpend, unspentTransactions = unspentTransactions[0], unspentTransactions[1:]
|
||||
spendingTransactions := generateTransactionsWithMultipleOutputs(t, payAddressKeyPair, payToPayAddressScript, transactionToSpend)
|
||||
transactions = append(transactions, spendingTransactions...)
|
||||
unspentTransactions = append(unspentTransactions, spendingTransactions...)
|
||||
}
|
||||
log.Infof("Generated %d transactions", len(transactions))
|
||||
}
|
||||
|
||||
transactions = transactions[:amountToSubmit]
|
||||
log.Infof("Submitting %d transactions", len(transactions))
|
||||
|
||||
for i, transaction := range transactions {
|
||||
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
||||
_, err := rpcClient.SubmitTransaction(rpcTransaction)
|
||||
if err != nil {
|
||||
if ignoreOrphanRejects && strings.Contains(err.Error(), "orphan") {
|
||||
continue
|
||||
}
|
||||
t.Fatalf("SubmitTransaction: %+v", err)
|
||||
}
|
||||
log.Infof("Submitted %d transactions", i+1)
|
||||
}
|
||||
}
|
||||
|
||||
func mineBlockAndGetCoinbaseTransaction(t *testing.T, rpcClient *rpcclient.RPCClient) *externalapi.DomainTransaction {
|
||||
getBlockTemplateResponse, err := rpcClient.GetBlockTemplate(payAddress)
|
||||
if err != nil {
|
||||
t.Fatalf("GetBlockTemplate: %+v", err)
|
||||
}
|
||||
templateBlock, err := appmessage.RPCBlockToDomainBlock(getBlockTemplateResponse.Block)
|
||||
if err != nil {
|
||||
t.Fatalf("RPCBlockToDomainBlock: %+v", err)
|
||||
}
|
||||
mine.SolveBlock(templateBlock)
|
||||
_, err = rpcClient.SubmitBlock(templateBlock)
|
||||
if err != nil {
|
||||
t.Fatalf("SubmitBlock: %+v", err)
|
||||
}
|
||||
return templateBlock.Transactions[transactionhelper.CoinbaseTransactionIndex]
|
||||
}
|
||||
|
||||
func generateTransactionsWithMultipleOutputs(t *testing.T,
|
||||
payAddressKeyPair *secp256k1.SchnorrKeyPair, payToPayAddressScript *externalapi.ScriptPublicKey,
|
||||
fundingTransaction *externalapi.DomainTransaction) []*externalapi.DomainTransaction {
|
||||
|
||||
var transactions []*externalapi.DomainTransaction
|
||||
for fundingTransactionOutputIndex, fundingTransactionOutput := range fundingTransaction.Outputs {
|
||||
if fundingTransactionOutput.Value < transactionFee {
|
||||
continue
|
||||
}
|
||||
outputValue := (fundingTransactionOutput.Value - transactionFee) / outputsPerTransaction
|
||||
|
||||
fundingTransactionID := consensushashing.TransactionID(fundingTransaction)
|
||||
spendingTransactionInputs := []*externalapi.DomainTransactionInput{
|
||||
{
|
||||
PreviousOutpoint: externalapi.DomainOutpoint{
|
||||
TransactionID: *fundingTransactionID,
|
||||
Index: uint32(fundingTransactionOutputIndex),
|
||||
},
|
||||
UTXOEntry: utxopkg.NewUTXOEntry(
|
||||
fundingTransactionOutput.Value,
|
||||
payToPayAddressScript,
|
||||
false,
|
||||
0),
|
||||
},
|
||||
}
|
||||
|
||||
spendingTransactionOutputs := make([]*externalapi.DomainTransactionOutput, outputsPerTransaction)
|
||||
for i := 0; i < outputsPerTransaction; i++ {
|
||||
spendingTransactionOutputs[i] = &externalapi.DomainTransactionOutput{
|
||||
Value: outputValue,
|
||||
ScriptPublicKey: payToPayAddressScript,
|
||||
}
|
||||
}
|
||||
|
||||
spendingTransaction := &externalapi.DomainTransaction{
|
||||
Version: constants.MaxTransactionVersion,
|
||||
Inputs: spendingTransactionInputs,
|
||||
Outputs: spendingTransactionOutputs,
|
||||
LockTime: 0,
|
||||
SubnetworkID: subnetworks.SubnetworkIDNative,
|
||||
Gas: 0,
|
||||
Payload: nil,
|
||||
}
|
||||
|
||||
for spendingTransactionInputIndex, spendingTransactionInput := range spendingTransactionInputs {
|
||||
signatureScript, err := txscript.SignatureScript(
|
||||
spendingTransaction,
|
||||
spendingTransactionInputIndex,
|
||||
consensushashing.SigHashAll,
|
||||
payAddressKeyPair,
|
||||
&consensushashing.SighashReusedValues{})
|
||||
if err != nil {
|
||||
t.Fatalf("SignatureScript: %+v", err)
|
||||
}
|
||||
spendingTransactionInput.SignatureScript = signatureScript
|
||||
}
|
||||
|
||||
transactions = append(transactions, spendingTransaction)
|
||||
}
|
||||
return transactions
|
||||
}
|
||||
|
||||
func decodePayAddressKeyPair(t *testing.T) *secp256k1.SchnorrKeyPair {
|
||||
privateKeyBytes, err := hex.DecodeString(payAddressPrivateKey)
|
||||
if err != nil {
|
||||
t.Fatalf("DecodeString: %+v", err)
|
||||
}
|
||||
keyPair, err := secp256k1.DeserializeSchnorrPrivateKeyFromSlice(privateKeyBytes)
|
||||
if err != nil {
|
||||
t.Fatalf("DeserializeSchnorrPrivateKeyFromSlice: %+v", err)
|
||||
}
|
||||
return keyPair
|
||||
}
|
||||
|
||||
func buildPayToPayAddressScript(t *testing.T) *externalapi.ScriptPublicKey {
|
||||
address, err := util.DecodeAddress(payAddress, dagconfig.SimnetParams.Prefix)
|
||||
if err != nil {
|
||||
t.Fatalf("DecodeAddress: %+v", err)
|
||||
}
|
||||
script, err := txscript.PayToAddrScript(address)
|
||||
if err != nil {
|
||||
t.Fatalf("PayToAddrScript: %+v", err)
|
||||
}
|
||||
return script
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus"
|
||||
"github.com/kaspanet/kaspad/stability-tests/common"
|
||||
"github.com/kaspanet/kaspad/stability-tests/common/mine"
|
||||
"github.com/kaspanet/kaspad/stability-tests/common/rpc"
|
||||
@@ -34,9 +33,7 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
consensusConfig := consensus.Config{Params: *cfg.NetParams()}
|
||||
|
||||
err = mine.FromFile(cfg.DAGFile, &consensusConfig, rpcClient, dataDir)
|
||||
err = mine.FromFile(cfg.DAGFile, cfg.NetParams(), rpcClient, dataDir)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "error in mine.FromFile"))
|
||||
}
|
||||
|
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user