kaspad/domain/consensus/test_consensus.go
Michael Sutton c9b591f2d3
Final reindex algorithm (#1430)
* Mine JSON

* [Reindex tests] add test_params and validate_mining flag to test_consensus

* Rename file and extend tests

* Ignore local test datasets

* Use spaces over tabs

* Reindex algorithm - full algorithm, initial commit, some tests fail

* Reindex algorithm - a few critical fixes

* Reindex algorithm - move reindex struct and all related operations to new file

* Reindex algorithm - added a validateIntervals method and modified tests to use it (instead of exact comparisons)

* Reindex algorithm - modified reindexIntervals to receive the new child as argument and fixed an important related bug

* Reindex attack tests - move logic to helper function and add stretch test

* Reindex algorithm - variable names and some comments

* Reindex algorithm - minor changes

* Reindex algorithm - minor changes 2

* Reindex algorithm - extended stretch test

* Reindex algorithm - small fix to validate function

* Reindex tests - move tests and add DAG files

* go format fixes

* TestParams doc comment

* Reindex tests - exact comparisons are not needed

* Update to version 0.8.6

* Remove TestParams and use AddUTXOInvalidHeader instead

* Use gzipeed test files

* This unintended change somehow slipped in through branch merges

* Rename test

* Move interval increase/decrease methods to reachability interval file

* Addressing a bunch of minor review comments

* Addressed a few more minor review comments

* Make code of offsetSiblingsBefore and offsetSiblingsAfter symmetric

* Optimize reindex logic in cases where reorg occurs + reorg test

* Do not change reindex root too fast (on reorg)

* Some comments

* A few more comments

* Addressing review comments

* Remove TestNoAttackAlternateReorg and assert chain attack

* Minor

Co-authored-by: Elichai Turkel <elichai.turkel@gmail.com>
Co-authored-by: Mike Zak <feanorr@gmail.com>
Co-authored-by: Ori Newman <orinewman1@gmail.com>
2021-01-27 17:09:20 +02:00

196 lines
5.7 KiB
Go

package consensus
import (
"encoding/json"
"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/consensushashing"
"github.com/kaspanet/kaspad/domain/dagconfig"
"github.com/kaspanet/kaspad/infrastructure/db/database"
"github.com/pkg/errors"
"io"
)
type testConsensus struct {
*consensus
dagParams *dagconfig.Params
database database.Database
testBlockBuilder testapi.TestBlockBuilder
testReachabilityManager testapi.TestReachabilityManager
testConsensusStateManager testapi.TestConsensusStateManager
testTransactionValidator testapi.TestTransactionValidator
}
func (tc *testConsensus) DAGParams() *dagconfig.Params {
return tc.dagParams
}
func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash,
coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (
*externalapi.DomainBlock, model.UTXODiff, error) {
// Require write lock because BuildBlockWithParents stages temporary data
tc.lock.Lock()
defer tc.lock.Unlock()
block, diff, err := tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions)
if err != nil {
return nil, nil, err
}
return block, diff, nil
}
func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.BlockInsertionResult, 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, nil, err
}
blockInsertionResult, err := tc.blockProcessor.ValidateAndInsertBlock(block)
if err != nil {
return nil, nil, err
}
return consensushashing.BlockHash(block), blockInsertionResult, nil
}
func (tc *testConsensus) AddUTXOInvalidHeader(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash,
*externalapi.BlockInsertionResult, error) {
// Require write lock because BuildBlockWithParents stages temporary data
tc.lock.Lock()
defer tc.lock.Unlock()
header, err := tc.testBlockBuilder.BuildUTXOInvalidHeader(parentHashes)
if err != nil {
return nil, nil, err
}
blockInsertionResult, err := tc.blockProcessor.ValidateAndInsertBlock(&externalapi.DomainBlock{
Header: header,
Transactions: nil,
})
if err != nil {
return nil, nil, err
}
return consensushashing.HeaderHash(header), blockInsertionResult, nil
}
func (tc *testConsensus) AddUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash,
*externalapi.BlockInsertionResult, error) {
// Require write lock because BuildBlockWithParents stages temporary data
tc.lock.Lock()
defer tc.lock.Unlock()
block, err := tc.testBlockBuilder.BuildUTXOInvalidBlock(parentHashes)
if err != nil {
return nil, nil, err
}
blockInsertionResult, err := tc.blockProcessor.ValidateAndInsertBlock(block)
if err != nil {
return nil, nil, err
}
return consensushashing.BlockHash(block), blockInsertionResult, nil
}
func (tc *testConsensus) MineJSON(r io.Reader) (tips []*externalapi.DomainHash, err error) {
// jsonBlock is a json representation of a block in mine format
type jsonBlock struct {
ID string `json:"id"`
Parents []string `json:"parents"`
}
tipSet := map[externalapi.DomainHash]*externalapi.DomainHash{}
tipSet[*tc.dagParams.GenesisHash] = tc.dagParams.GenesisHash
parentsMap := make(map[string]*externalapi.DomainHash)
parentsMap["0"] = tc.dagParams.GenesisHash
decoder := json.NewDecoder(r)
// read open bracket
_, err = decoder.Token()
if err != nil {
return nil, err
}
// while the array contains values
for decoder.More() {
var block jsonBlock
// decode an array value (Message)
err := decoder.Decode(&block)
if err != nil {
return nil, err
}
if block.ID == "0" {
continue
}
parentHashes := make([]*externalapi.DomainHash, len(block.Parents))
var ok bool
for i, parentID := range block.Parents {
parentHashes[i], ok = parentsMap[parentID]
if !ok {
return nil, errors.Errorf("Couldn't find blockID: %s", parentID)
}
delete(tipSet, *parentHashes[i])
}
blockHash, _, err := tc.AddUTXOInvalidHeader(parentHashes)
if err != nil {
return nil, err
}
parentsMap[block.ID] = blockHash
tipSet[*blockHash] = blockHash
}
tips = make([]*externalapi.DomainHash, len(tipSet))
i := 0
for _, v := range tipSet {
tips[i] = v
i++
}
return tips, nil
}
func (tc *testConsensus) BuildUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainBlock, error) {
// Require write lock because BuildBlockWithParents stages temporary data
tc.lock.Lock()
defer tc.lock.Unlock()
return tc.testBlockBuilder.BuildUTXOInvalidBlock(parentHashes)
}
func (tc *testConsensus) BuildHeaderWithParents(parentHashes []*externalapi.DomainHash) (externalapi.BlockHeader, error) {
// Require write lock because BuildUTXOInvalidHeader stages temporary data
tc.lock.Lock()
defer tc.lock.Unlock()
return tc.testBlockBuilder.BuildUTXOInvalidHeader(parentHashes)
}
func (tc *testConsensus) DiscardAllStores() {
tc.AcceptanceDataStore().Discard()
tc.BlockHeaderStore().Discard()
tc.BlockRelationStore().Discard()
tc.BlockStatusStore().Discard()
tc.BlockStore().Discard()
tc.ConsensusStateStore().Discard()
tc.GHOSTDAGDataStore().Discard()
tc.HeaderTipsStore().Discard()
tc.MultisetStore().Discard()
tc.PruningStore().Discard()
tc.ReachabilityDataStore().Discard()
tc.UTXODiffStore().Discard()
tc.HeadersSelectedChainStore().Discard()
}