[NOD-1529] Add getters + AddBlock to TestConsensus (#1025)

* [NOD-1529] Add all stores and processes to consensus, and add access to TestConsensus

* [NOD-1529] Move the getters of TestConsensus to separate file

* [NOD-1529] Add AddBlock to TestConsensus

* [NOD-1529] Update NewTestConsensus to be more all-encompassing

* [NOD-1529] Remove test directory in teardown

* [NOD-1529] Add ForAllNets function

* [NOD-1529] Add comment
This commit is contained in:
Svarog 2020-11-11 12:31:13 +02:00 committed by GitHub
parent 4736213ba4
commit 135ffbd4f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 288 additions and 17 deletions

View File

@ -19,12 +19,28 @@ type consensus struct {
transactionValidator model.TransactionValidator
syncManager model.SyncManager
pastMedianTimeManager model.PastMedianTimeManager
blockValidator model.BlockValidator
coinbaseManager model.CoinbaseManager
dagTopologyManager model.DAGTopologyManager
dagTraversalManager model.DAGTraversalManager
difficultyManager model.DifficultyManager
ghostdagManager model.GHOSTDAGManager
headerTipsManager model.HeaderTipsManager
mergeDepthManager model.MergeDepthManager
pruningManager model.PruningManager
reachabilityManager model.ReachabilityManager
blockStore model.BlockStore
blockHeaderStore model.BlockHeaderStore
pruningStore model.PruningStore
ghostdagDataStore model.GHOSTDAGDataStore
blockStatusStore model.BlockStatusStore
blockStore model.BlockStore
blockHeaderStore model.BlockHeaderStore
pruningStore model.PruningStore
ghostdagDataStore model.GHOSTDAGDataStore
blockRelationStore model.BlockRelationStore
blockStatusStore model.BlockStatusStore
consensusStateStore model.ConsensusStateStore
headerTipsStore model.HeaderTipsStore
multisetStore model.MultisetStore
reachabilityDataStore model.ReachabilityDataStore
utxoDiffStore model.UTXODiffStore
}
// BuildBlock builds a block over the current state, with the transactions

View File

@ -1,8 +1,12 @@
package consensus
import (
"io/ioutil"
"os"
"sync"
"github.com/kaspanet/kaspad/infrastructure/db/database/ldb"
consensusdatabase "github.com/kaspanet/kaspad/domain/consensus/database"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/acceptancedatastore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/blockheaderstore"
@ -42,7 +46,7 @@ import (
// Factory instantiates new Consensuses
type Factory interface {
NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error)
NewTestConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (testapi.TestConsensus, error)
NewTestConsensus(dagParams *dagconfig.Params, testName string) (tc testapi.TestConsensus, teardown func(), err error)
}
type factory struct{}
@ -255,12 +259,27 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
transactionValidator: transactionValidator,
syncManager: syncManager,
pastMedianTimeManager: pastMedianTimeManager,
blockValidator: blockValidator,
coinbaseManager: coinbaseManager,
dagTopologyManager: dagTopologyManager,
dagTraversalManager: dagTraversalManager,
difficultyManager: difficultyManager,
ghostdagManager: ghostdagManager,
headerTipsManager: headerTipsManager,
mergeDepthManager: mergeDepthManager,
pruningManager: pruningManager,
reachabilityManager: reachabilityManager,
blockStore: blockStore,
blockHeaderStore: blockHeaderStore,
pruningStore: pruningStore,
ghostdagDataStore: ghostdagDataStore,
blockStatusStore: blockStatusStore,
blockStore: blockStore,
blockHeaderStore: blockHeaderStore,
pruningStore: pruningStore,
ghostdagDataStore: ghostdagDataStore,
blockStatusStore: blockStatusStore,
blockRelationStore: blockRelationStore,
consensusStateStore: consensusStateStore,
headerTipsStore: headerTipsStore,
multisetStore: multisetStore,
reachabilityDataStore: reachabilityDataStore,
}
genesisInfo, err := c.GetBlockInfo(genesisHash)
@ -278,18 +297,32 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
return c, nil
}
func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (
testapi.TestConsensus, error) {
func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string) (
tc testapi.TestConsensus, teardown func(), err error) {
testDatabaseDir, err := ioutil.TempDir("", testName)
if err != nil {
return nil, nil, err
}
db, err := ldb.NewLevelDB(testDatabaseDir)
if err != nil {
return nil, nil, err
}
consensusAsInterface, err := f.NewConsensus(dagParams, db)
if err != nil {
return nil, err
return nil, nil, err
}
consensusAsImplementation := consensusAsInterface.(*consensus)
return &testConsensus{
tc = &testConsensus{
consensus: consensusAsImplementation,
testBlockBuilder: blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder),
}, nil
}
teardown = func() {
db.Close()
os.RemoveAll(testDatabaseDir)
}
return tc, teardown, nil
}

View File

@ -1,6 +1,9 @@
package testapi
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
)
// TestConsensus wraps the Consensus interface with some methods that are needed by tests only
type TestConsensus interface {
@ -8,4 +11,39 @@ type TestConsensus interface {
BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error)
// AddBlock builds a block with given information, solves it, and adds to the DAG.
// Returns the hash of the added block
AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, error)
AcceptanceDataStore() model.AcceptanceDataStore
BlockHeaderStore() model.BlockHeaderStore
BlockRelationStore() model.BlockRelationStore
BlockStatusStore() model.BlockStatusStore
BlockStore() model.BlockStore
ConsensusStateStore() model.ConsensusStateStore
GHOSTDAGDataStore() model.GHOSTDAGDataStore
HeaderTipsStore() model.HeaderTipsStore
MultisetStore() model.MultisetStore
PruningStore() model.PruningStore
ReachabilityDataStore() model.ReachabilityDataStore
UTXODiffStore() model.UTXODiffStore
BlockBuilder() model.BlockBuilder
BlockProcessor() model.BlockProcessor
BlockValidator() model.BlockValidator
CoinbaseManager() model.CoinbaseManager
ConsensusStateManager() model.ConsensusStateManager
DAGTopologyManager() model.DAGTopologyManager
DAGTraversalManager() model.DAGTraversalManager
DifficultyManager() model.DifficultyManager
GHOSTDAGManager() model.GHOSTDAGManager
HeaderTipsManager() model.HeaderTipsManager
MergeDepthManager() model.MergeDepthManager
PastMedianTimeManager() model.PastMedianTimeManager
PruningManager() model.PruningManager
ReachabilityManager() model.ReachabilityManager
SyncManager() model.SyncManager
TransactionValidator() model.TransactionValidator
}

View File

@ -1,8 +1,14 @@
package consensus
import (
"errors"
"math"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
"github.com/kaspanet/kaspad/util"
)
type testConsensus struct {
@ -19,3 +25,39 @@ func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.Domai
return tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions)
}
func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, error) {
// Require write lock because BuildBlockWithParents stages temporary data
tc.lock.Lock()
defer tc.lock.Unlock()
block, err := tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions)
if err != nil {
return nil, err
}
solveBlock(block)
err = tc.ValidateAndInsertBlock(block)
if err != nil {
return nil, err
}
return consensusserialization.BlockHash(block), nil
}
func solveBlock(block *externalapi.DomainBlock) {
targetDifficulty := util.CompactToBig(block.Header.Bits)
for i := uint64(0); i < math.MaxUint64; i++ {
block.Header.Nonce = i
hash := consensusserialization.BlockHash(block)
if hashes.ToBig(hash).Cmp(targetDifficulty) <= 0 {
return
}
}
panic(errors.New("went over all the nonce space and couldn't find a single one that gives a valid block"))
}

View File

@ -0,0 +1,115 @@
package consensus
import "github.com/kaspanet/kaspad/domain/consensus/model"
func (tc *testConsensus) AcceptanceDataStore() model.AcceptanceDataStore {
return tc.AcceptanceDataStore()
}
func (tc *testConsensus) BlockHeaderStore() model.BlockHeaderStore {
return tc.blockHeaderStore
}
func (tc *testConsensus) BlockRelationStore() model.BlockRelationStore {
return tc.blockRelationStore
}
func (tc *testConsensus) BlockStatusStore() model.BlockStatusStore {
return tc.blockStatusStore
}
func (tc *testConsensus) BlockStore() model.BlockStore {
return tc.blockStore
}
func (tc *testConsensus) ConsensusStateStore() model.ConsensusStateStore {
return tc.consensusStateStore
}
func (tc *testConsensus) GHOSTDAGDataStore() model.GHOSTDAGDataStore {
return tc.ghostdagDataStore
}
func (tc *testConsensus) HeaderTipsStore() model.HeaderTipsStore {
return tc.headerTipsStore
}
func (tc *testConsensus) MultisetStore() model.MultisetStore {
return tc.multisetStore
}
func (tc *testConsensus) PruningStore() model.PruningStore {
return tc.pruningStore
}
func (tc *testConsensus) ReachabilityDataStore() model.ReachabilityDataStore {
return tc.reachabilityDataStore
}
func (tc *testConsensus) UTXODiffStore() model.UTXODiffStore {
return tc.utxoDiffStore
}
func (tc *testConsensus) BlockBuilder() model.BlockBuilder {
return tc.blockBuilder
}
func (tc *testConsensus) BlockProcessor() model.BlockProcessor {
return tc.blockProcessor
}
func (tc *testConsensus) BlockValidator() model.BlockValidator {
return tc.blockValidator
}
func (tc *testConsensus) CoinbaseManager() model.CoinbaseManager {
return tc.coinbaseManager
}
func (tc *testConsensus) ConsensusStateManager() model.ConsensusStateManager {
return tc.consensusStateManager
}
func (tc *testConsensus) DAGTopologyManager() model.DAGTopologyManager {
return tc.dagTopologyManager
}
func (tc *testConsensus) DAGTraversalManager() model.DAGTraversalManager {
return tc.dagTraversalManager
}
func (tc *testConsensus) DifficultyManager() model.DifficultyManager {
return tc.difficultyManager
}
func (tc *testConsensus) GHOSTDAGManager() model.GHOSTDAGManager {
return tc.ghostdagManager
}
func (tc *testConsensus) HeaderTipsManager() model.HeaderTipsManager {
return tc.headerTipsManager
}
func (tc *testConsensus) MergeDepthManager() model.MergeDepthManager {
return tc.mergeDepthManager
}
func (tc *testConsensus) PastMedianTimeManager() model.PastMedianTimeManager {
return tc.pastMedianTimeManager
}
func (tc *testConsensus) PruningManager() model.PruningManager {
return tc.pruningManager
}
func (tc *testConsensus) ReachabilityManager() model.ReachabilityManager {
return tc.reachabilityManager
}
func (tc *testConsensus) SyncManager() model.SyncManager {
return tc.syncManager
}
func (tc *testConsensus) TransactionValidator() model.TransactionValidator {
return tc.transactionValidator
}

View File

@ -0,0 +1,27 @@
package testutils
import (
"testing"
"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, setDifficultyToMinimum bool, testFunc func(*testing.T, *dagconfig.Params)) {
allParams := []dagconfig.Params{
dagconfig.MainnetParams,
dagconfig.TestnetParams,
dagconfig.SimnetParams,
dagconfig.DevnetParams,
}
for _, params := range allParams {
if setDifficultyToMinimum {
params.DisableDifficultyAdjustment = dagconfig.SimnetParams.DisableDifficultyAdjustment
params.TargetTimePerBlock = dagconfig.SimnetParams.TargetTimePerBlock
}
testFunc(t, &params)
}
}