diff --git a/domain/consensus/database/serialization/block_ghostdag_data.go b/domain/consensus/database/serialization/block_ghostdag_data.go index 7525eefc8..1765104ba 100644 --- a/domain/consensus/database/serialization/block_ghostdag_data.go +++ b/domain/consensus/database/serialization/block_ghostdag_data.go @@ -1,12 +1,20 @@ package serialization -import "github.com/kaspanet/kaspad/domain/consensus/model" +import ( + "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" +) // BlockGHOSTDAGDataToDBBlockGHOSTDAGData converts BlockGHOSTDAGData to DbBlockGhostdagData func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData *model.BlockGHOSTDAGData) *DbBlockGhostdagData { + var selectedParent *DbHash + if blockGHOSTDAGData.SelectedParent != nil { + selectedParent = DomainHashToDbHash(blockGHOSTDAGData.SelectedParent) + } + return &DbBlockGhostdagData{ BlueScore: blockGHOSTDAGData.BlueScore, - SelectedParent: DomainHashToDbHash(blockGHOSTDAGData.SelectedParent), + SelectedParent: selectedParent, MergeSetBlues: DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetBlues), MergeSetReds: DomainHashesToDbHashes(blockGHOSTDAGData.MergeSetReds), BluesAnticoneSizes: bluesAnticoneSizesToDBBluesAnticoneSizes(blockGHOSTDAGData.BluesAnticoneSizes), @@ -15,9 +23,13 @@ func BlockGHOSTDAGDataToDBBlockGHOSTDAGData(blockGHOSTDAGData *model.BlockGHOSTD // DBBlockGHOSTDAGDataToBlockGHOSTDAGData converts DbBlockGhostdagData to BlockGHOSTDAGData func DBBlockGHOSTDAGDataToBlockGHOSTDAGData(dbBlockGHOSTDAGData *DbBlockGhostdagData) (*model.BlockGHOSTDAGData, error) { - selectedParent, err := DbHashToDomainHash(dbBlockGHOSTDAGData.SelectedParent) - if err != nil { - return nil, err + var selectedParent *externalapi.DomainHash + if dbBlockGHOSTDAGData.SelectedParent != nil { + var err error + selectedParent, err = DbHashToDomainHash(dbBlockGHOSTDAGData.SelectedParent) + if err != nil { + return nil, err + } } mergetSetBlues, err := DbHashesToDomainHashes(dbBlockGHOSTDAGData.MergeSetBlues) diff --git a/domain/consensus/database/serialization/reachability_tree_node.go b/domain/consensus/database/serialization/reachability_tree_node.go index 68210a6b0..f181375ca 100644 --- a/domain/consensus/database/serialization/reachability_tree_node.go +++ b/domain/consensus/database/serialization/reachability_tree_node.go @@ -2,12 +2,18 @@ package serialization import ( "github.com/kaspanet/kaspad/domain/consensus/model" + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) func reachablityTreeNodeToDBReachablityTreeNode(reachabilityTreeNode *model.ReachabilityTreeNode) *DbReachabilityTreeNode { + var parent *DbHash + if reachabilityTreeNode.Parent != nil { + parent = DomainHashToDbHash(reachabilityTreeNode.Parent) + } + return &DbReachabilityTreeNode{ Children: DomainHashesToDbHashes(reachabilityTreeNode.Children), - Parent: DomainHashToDbHash(reachabilityTreeNode.Parent), + Parent: parent, Interval: reachablityIntervalToDBReachablityInterval(reachabilityTreeNode.Interval), } } @@ -18,9 +24,13 @@ func dbReachablityTreeNodeToReachablityTreeNode(dbReachabilityTreeNode *DbReacha return nil, err } - parent, err := DbHashToDomainHash(dbReachabilityTreeNode.Parent) - if err != nil { - return nil, err + var parent *externalapi.DomainHash + if dbReachabilityTreeNode.Parent != nil { + var err error + parent, err = DbHashToDomainHash(dbReachabilityTreeNode.Parent) + if err != nil { + return nil, err + } } return &model.ReachabilityTreeNode{ diff --git a/domain/consensus/database/transaction.go b/domain/consensus/database/transaction.go index feb1bf8be..807150bbe 100644 --- a/domain/consensus/database/transaction.go +++ b/domain/consensus/database/transaction.go @@ -9,23 +9,23 @@ type dbTransaction struct { transaction database.Transaction } -func (d dbTransaction) Put(key model.DBKey, value []byte) error { +func (d *dbTransaction) Put(key model.DBKey, value []byte) error { return d.transaction.Put(dbKeyToDatabaseKey(key), value) } -func (d dbTransaction) Delete(key model.DBKey) error { +func (d *dbTransaction) Delete(key model.DBKey) error { return d.transaction.Delete(dbKeyToDatabaseKey(key)) } -func (d dbTransaction) Rollback() error { +func (d *dbTransaction) Rollback() error { return d.transaction.Rollback() } -func (d dbTransaction) Commit() error { - return d.Commit() +func (d *dbTransaction) Commit() error { + return d.transaction.Commit() } -func (d dbTransaction) RollbackUnlessClosed() error { +func (d *dbTransaction) RollbackUnlessClosed() error { return d.RollbackUnlessClosed() } diff --git a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go index 28bfdb901..974c86022 100644 --- a/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go +++ b/domain/consensus/datastructures/blockrelationstore/blockrelationstore.go @@ -63,6 +63,14 @@ func (brs *blockRelationStore) BlockRelation(dbContext model.DBReader, blockHash return brs.deserializeBlockRelations(blockRelationsBytes) } +func (brs *blockRelationStore) Has(dbContext model.DBReader, blockHash *externalapi.DomainHash) (bool, error) { + if _, ok := brs.staging[*blockHash]; ok { + return true, nil + } + + return dbContext.Has(brs.hashAsKey(blockHash)) +} + func (brs *blockRelationStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey { return bucket.Key(hash[:]) } diff --git a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go index 1ab46fbab..c2cf22ef1 100644 --- a/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go +++ b/domain/consensus/datastructures/consensusstatestore/consensusstatestore.go @@ -18,14 +18,14 @@ func New() model.ConsensusStateStore { return &consensusStateStore{} } -func (c consensusStateStore) Discard() { +func (c *consensusStateStore) Discard() { c.stagedTips = nil c.stagedVirtualUTXODiff = nil c.stagedVirtualDiffParents = nil c.stagedVirtualUTXOSet = nil } -func (c consensusStateStore) Commit(dbTx model.DBTransaction) error { +func (c *consensusStateStore) Commit(dbTx model.DBTransaction) error { err := c.commitTips(dbTx) if err != nil { return err @@ -50,7 +50,7 @@ func (c consensusStateStore) Commit(dbTx model.DBTransaction) error { return nil } -func (c consensusStateStore) IsStaged() bool { +func (c *consensusStateStore) IsStaged() bool { return c.stagedTips != nil || c.stagedVirtualDiffParents != nil || c.stagedVirtualUTXODiff != nil diff --git a/domain/consensus/datastructures/consensusstatestore/tips.go b/domain/consensus/datastructures/consensusstatestore/tips.go index f9e3a8546..b27418227 100644 --- a/domain/consensus/datastructures/consensusstatestore/tips.go +++ b/domain/consensus/datastructures/consensusstatestore/tips.go @@ -9,7 +9,7 @@ import ( var tipsKey = dbkeys.MakeBucket().Key([]byte("tips")) -func (c consensusStateStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) { +func (c *consensusStateStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) { if c.stagedTips != nil { return c.stagedTips, nil } @@ -22,11 +22,11 @@ func (c consensusStateStore) Tips(dbContext model.DBReader) ([]*externalapi.Doma return hashes.DeserializeHashSlice(tipsBytes) } -func (c consensusStateStore) StageTips(tipHashes []*externalapi.DomainHash) { +func (c *consensusStateStore) StageTips(tipHashes []*externalapi.DomainHash) { c.stagedTips = tipHashes } -func (c consensusStateStore) commitTips(dbTx model.DBTransaction) error { +func (c *consensusStateStore) commitTips(dbTx model.DBTransaction) error { tipsBytes := hashes.SerializeHashSlice(c.stagedTips) err := dbTx.Put(tipsKey, tipsBytes) diff --git a/domain/consensus/datastructures/consensusstatestore/utxo.go b/domain/consensus/datastructures/consensusstatestore/utxo.go index b5ace883e..fc225fff0 100644 --- a/domain/consensus/datastructures/consensusstatestore/utxo.go +++ b/domain/consensus/datastructures/consensusstatestore/utxo.go @@ -18,7 +18,7 @@ func utxoKey(outpoint *externalapi.DomainOutpoint) (model.DBKey, error) { return utxoSetBucket.Key(serializedOutpoint), nil } -func (c consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff *model.UTXODiff) error { +func (c *consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff *model.UTXODiff) error { if c.stagedVirtualUTXOSet != nil { return errors.New("cannot stage virtual UTXO diff while virtual UTXO set is staged") } @@ -27,11 +27,15 @@ func (c consensusStateStore) StageVirtualUTXODiff(virtualUTXODiff *model.UTXODif return nil } -func (c consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) error { +func (c *consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) error { if c.stagedVirtualUTXOSet != nil { return errors.New("cannot commit virtual UTXO diff while virtual UTXO set is staged") } + if c.stagedVirtualUTXODiff == nil { + return nil + } + for toRemoveOutpoint := range c.stagedVirtualUTXODiff.ToRemove { dbKey, err := utxoKey(&toRemoveOutpoint) if err != nil { @@ -61,7 +65,7 @@ func (c consensusStateStore) commitVirtualUTXODiff(dbTx model.DBTransaction) err return nil } -func (c consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) error { +func (c *consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) error { if c.stagedVirtualUTXODiff != nil { return errors.New("cannot commit virtual UTXO set while virtual UTXO diff is staged") } @@ -84,7 +88,7 @@ func (c consensusStateStore) commitVirtualUTXOSet(dbTx model.DBTransaction) erro return nil } -func (c consensusStateStore) UTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) ( +func (c *consensusStateStore) UTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) ( *externalapi.UTXOEntry, error) { if c.stagedVirtualUTXOSet != nil { @@ -94,7 +98,7 @@ func (c consensusStateStore) UTXOByOutpoint(dbContext model.DBReader, outpoint * return c.utxoByOutpointFromStagedVirtualUTXODiff(dbContext, outpoint) } -func (c consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader, +func (c *consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) ( *externalapi.UTXOEntry, error) { @@ -120,7 +124,7 @@ func (c consensusStateStore) utxoByOutpointFromStagedVirtualUTXODiff(dbContext m return deserializeUTXOEntry(serializedUTXOEntry) } -func (c consensusStateStore) utxoByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) ( +func (c *consensusStateStore) utxoByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) ( *externalapi.UTXOEntry, error) { if utxoEntry, ok := c.stagedVirtualUTXOSet[*outpoint]; ok { return utxoEntry, nil @@ -129,7 +133,7 @@ func (c consensusStateStore) utxoByOutpointFromStagedVirtualUTXOSet(outpoint *ex return nil, errors.Errorf("outpoint was not found") } -func (c consensusStateStore) HasUTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) { +func (c *consensusStateStore) HasUTXOByOutpoint(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) { if c.stagedVirtualUTXOSet != nil { return c.hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint), nil } @@ -137,7 +141,7 @@ func (c consensusStateStore) HasUTXOByOutpoint(dbContext model.DBReader, outpoin return c.hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContext, outpoint) } -func (c consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader, +func (c *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContext model.DBReader, outpoint *externalapi.DomainOutpoint) (bool, error) { if _, ok := c.stagedVirtualUTXODiff.ToRemove[*outpoint]; ok { return false, nil @@ -154,12 +158,12 @@ func (c consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXODiff(dbContex return dbContext.Has(key) } -func (c consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) bool { +func (c *consensusStateStore) hasUTXOByOutpointFromStagedVirtualUTXOSet(outpoint *externalapi.DomainOutpoint) bool { _, ok := c.stagedVirtualUTXOSet[*outpoint] return ok } -func (c consensusStateStore) VirtualUTXOSetIterator(dbContext model.DBReader) (model.ReadOnlyUTXOSetIterator, error) { +func (c *consensusStateStore) VirtualUTXOSetIterator(dbContext model.DBReader) (model.ReadOnlyUTXOSetIterator, error) { cursor, err := dbContext.Cursor(utxoSetBucket) if err != nil { return nil, err @@ -204,7 +208,7 @@ func (u utxoSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry return outpoint, utxoEntry, nil } -func (c consensusStateStore) StageVirtualUTXOSet(virtualUTXOSetIterator model.ReadOnlyUTXOSetIterator) error { +func (c *consensusStateStore) StageVirtualUTXOSet(virtualUTXOSetIterator model.ReadOnlyUTXOSetIterator) error { if c.stagedVirtualUTXODiff != nil { return errors.New("cannot stage virtual UTXO set while virtual UTXO diff is staged") } diff --git a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go index bfd61c28a..3915a67d0 100644 --- a/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go +++ b/domain/consensus/datastructures/consensusstatestore/virtual_diff_parents.go @@ -9,7 +9,7 @@ import ( var virtualDiffParentsKey = dbkeys.MakeBucket().Key([]byte("virtual-diff-parents")) -func (c consensusStateStore) VirtualDiffParents(dbContext model.DBReader) ([]*externalapi.DomainHash, error) { +func (c *consensusStateStore) VirtualDiffParents(dbContext model.DBReader) ([]*externalapi.DomainHash, error) { if c.stagedVirtualDiffParents != nil { return c.stagedVirtualDiffParents, nil } @@ -22,11 +22,11 @@ func (c consensusStateStore) VirtualDiffParents(dbContext model.DBReader) ([]*ex return hashes.DeserializeHashSlice(virtualDiffParentsBytes) } -func (c consensusStateStore) StageVirtualDiffParents(tipHashes []*externalapi.DomainHash) { +func (c *consensusStateStore) StageVirtualDiffParents(tipHashes []*externalapi.DomainHash) { c.stagedVirtualDiffParents = tipHashes } -func (c consensusStateStore) commitVirtualDiffParents(dbTx model.DBTransaction) error { +func (c *consensusStateStore) commitVirtualDiffParents(dbTx model.DBTransaction) error { virtualDiffParentsBytes := hashes.SerializeHashSlice(c.stagedVirtualDiffParents) err := dbTx.Put(virtualDiffParentsKey, virtualDiffParentsBytes) diff --git a/domain/consensus/datastructures/headertipsstore/headertipsstore.go b/domain/consensus/datastructures/headertipsstore/headertipsstore.go index 341d214ea..a846a982b 100644 --- a/domain/consensus/datastructures/headertipsstore/headertipsstore.go +++ b/domain/consensus/datastructures/headertipsstore/headertipsstore.go @@ -14,28 +14,46 @@ type headerTipsStore struct { staging []*externalapi.DomainHash } -func (h headerTipsStore) Discard() { +func (h *headerTipsStore) HasTips(dbContext model.DBReader) (bool, error) { + if h.staging != nil { + return len(h.staging) > 0, nil + } + + return dbContext.Has(headerTipsKey) +} + +func (h *headerTipsStore) Discard() { h.staging = nil } -func (h headerTipsStore) Commit(dbTx model.DBTransaction) error { +func (h *headerTipsStore) Commit(dbTx model.DBTransaction) error { + if h.staging == nil { + return nil + } + tipsBytes, err := h.serializeTips(h.staging) if err != nil { return err } - return dbTx.Put(headerTipsKey, tipsBytes) + err = dbTx.Put(headerTipsKey, tipsBytes) + if err != nil { + return err + } + + h.Discard() + return nil } -func (h headerTipsStore) Stage(tips []*externalapi.DomainHash) { +func (h *headerTipsStore) Stage(tips []*externalapi.DomainHash) { h.staging = tips } -func (h headerTipsStore) IsStaged() bool { +func (h *headerTipsStore) IsStaged() bool { return h.staging != nil } -func (h headerTipsStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) { +func (h *headerTipsStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) { if h.staging != nil { return h.staging, nil } @@ -48,12 +66,12 @@ func (h headerTipsStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHa return h.deserializeTips(tipsBytes) } -func (h headerTipsStore) serializeTips(tips []*externalapi.DomainHash) ([]byte, error) { +func (h *headerTipsStore) serializeTips(tips []*externalapi.DomainHash) ([]byte, error) { dbTips := serialization.HeaderTipsToDBHeaderTips(tips) return proto.Marshal(dbTips) } -func (h headerTipsStore) deserializeTips(tipsBytes []byte) ([]*externalapi.DomainHash, error) { +func (h *headerTipsStore) deserializeTips(tipsBytes []byte) ([]*externalapi.DomainHash, error) { dbTips := &serialization.DbHeaderTips{} err := proto.Unmarshal(tipsBytes, dbTips) if err != nil { diff --git a/domain/consensus/datastructures/pruningstore/pruningstore.go b/domain/consensus/datastructures/pruningstore/pruningstore.go index 512d94bc0..d1188fda5 100644 --- a/domain/consensus/datastructures/pruningstore/pruningstore.go +++ b/domain/consensus/datastructures/pruningstore/pruningstore.go @@ -41,24 +41,27 @@ func (ps *pruningStore) Discard() { } func (ps *pruningStore) Commit(dbTx model.DBTransaction) error { - pruningPointBytes, err := ps.serializePruningPoint(ps.pruningPointStaging) - if err != nil { - return err + if ps.pruningPointStaging != nil { + pruningPointBytes, err := ps.serializePruningPoint(ps.pruningPointStaging) + if err != nil { + return err + } + err = dbTx.Put(pruningBlockHashKey, pruningPointBytes) + if err != nil { + return err + } } - err = dbTx.Put(pruningBlockHashKey, pruningPointBytes) - if err != nil { - return err - } + if ps.serializedUTXOSetStaging != nil { + utxoSetBytes, err := ps.serializeUTXOSetBytes(ps.serializedUTXOSetStaging) + if err != nil { + return err + } - utxoSetBytes, err := ps.serializeUTXOSetBytes(ps.serializedUTXOSetStaging) - if err != nil { - return err - } - - err = dbTx.Put(pruningSerializedUTXOSetkey, utxoSetBytes) - if err != nil { - return err + err = dbTx.Put(pruningSerializedUTXOSetkey, utxoSetBytes) + if err != nil { + return err + } } ps.Discard() diff --git a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go index 18daf8ce8..355496483 100644 --- a/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go +++ b/domain/consensus/datastructures/reachabilitydatastore/reachabilitydatastore.go @@ -88,6 +88,14 @@ func (rds *reachabilityDataStore) ReachabilityData(dbContext model.DBReader, return rds.deserializeReachabilityData(reachabilityDataBytes) } +func (rds *reachabilityDataStore) HasReachabilityData(dbContext model.DBReader, blockHash *externalapi.DomainHash) (bool, error) { + if _, ok := rds.reachabilityDataStaging[*blockHash]; ok { + return true, nil + } + + return dbContext.Has(rds.reachabilityDataBlockHashAsKey(blockHash)) +} + // ReachabilityReindexRoot returns the current reachability reindex root func (rds *reachabilityDataStore) ReachabilityReindexRoot(dbContext model.DBReader) (*externalapi.DomainHash, error) { if rds.reachabilityReindexRootStaging != nil { diff --git a/domain/consensus/factory.go b/domain/consensus/factory.go index 777ad12a6..a2e0d6fe7 100644 --- a/domain/consensus/factory.go +++ b/domain/consensus/factory.go @@ -221,7 +221,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat blockHeaderStore, headerTipsStore) - return &consensus{ + c := &consensus{ databaseContext: dbManager, blockProcessor: blockProcessor, @@ -235,7 +235,21 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat pruningStore: pruningStore, ghostdagDataStore: ghostdagDataStore, blockStatusStore: blockStatusStore, - }, nil + } + + genesisInfo, err := c.GetBlockInfo(genesisHash) + if err != nil { + return nil, err + } + + if !genesisInfo.Exists { + err = c.ValidateAndInsertBlock(dagParams.GenesisBlock) + if err != nil { + return nil, err + } + } + + return c, nil } // NewFactory creates a new Consensus factory diff --git a/domain/consensus/factory_test.go b/domain/consensus/factory_test.go new file mode 100644 index 000000000..9db43b9a9 --- /dev/null +++ b/domain/consensus/factory_test.go @@ -0,0 +1,29 @@ +package consensus + +import ( + "github.com/kaspanet/kaspad/domain/dagconfig" + "github.com/kaspanet/kaspad/infrastructure/db/database/ldb" + "io/ioutil" + "testing" +) + +func TestNewConsensus(t *testing.T) { + f := NewFactory() + + dagParams := &dagconfig.DevnetParams + + tmpDir, err := ioutil.TempDir("", "TestNewConsensus") + if err != nil { + return + } + + db, err := ldb.NewLevelDB(tmpDir) + if err != nil { + t.Fatalf("error in NewLevelDB: %s", err) + } + + _, err = f.NewConsensus(dagParams, db) + if err != nil { + t.Fatalf("error in NewConsensus: %+v", err) + } +} diff --git a/domain/consensus/model/externalapi/sync.go b/domain/consensus/model/externalapi/sync.go index 52038e002..9b23d2389 100644 --- a/domain/consensus/model/externalapi/sync.go +++ b/domain/consensus/model/externalapi/sync.go @@ -4,6 +4,7 @@ package externalapi // states of the consensus const ( SyncStateNormal SyncState = iota + SyncStateMissingGenesis SyncStateHeadersFirst SyncStateMissingUTXOSet SyncStateMissingBlockBodies diff --git a/domain/consensus/model/interface_datastructures_blockrelationstore.go b/domain/consensus/model/interface_datastructures_blockrelationstore.go index f429969b1..b4274c68e 100644 --- a/domain/consensus/model/interface_datastructures_blockrelationstore.go +++ b/domain/consensus/model/interface_datastructures_blockrelationstore.go @@ -8,4 +8,5 @@ type BlockRelationStore interface { StageBlockRelation(blockHash *externalapi.DomainHash, blockRelations *BlockRelations) IsStaged() bool BlockRelation(dbContext DBReader, blockHash *externalapi.DomainHash) (*BlockRelations, error) + Has(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) } diff --git a/domain/consensus/model/interface_datastructures_headertipsstore.go b/domain/consensus/model/interface_datastructures_headertipsstore.go index 01e501a61..df3bc6dca 100644 --- a/domain/consensus/model/interface_datastructures_headertipsstore.go +++ b/domain/consensus/model/interface_datastructures_headertipsstore.go @@ -8,4 +8,5 @@ type HeaderTipsStore interface { Stage(tips []*externalapi.DomainHash) IsStaged() bool Tips(dbContext DBReader) ([]*externalapi.DomainHash, error) + HasTips(dbContext DBReader) (bool, error) } diff --git a/domain/consensus/model/interface_datastructures_reachabilitydatastore.go b/domain/consensus/model/interface_datastructures_reachabilitydatastore.go index a7cb9a440..e1225b19e 100644 --- a/domain/consensus/model/interface_datastructures_reachabilitydatastore.go +++ b/domain/consensus/model/interface_datastructures_reachabilitydatastore.go @@ -9,5 +9,6 @@ type ReachabilityDataStore interface { StageReachabilityReindexRoot(reachabilityReindexRoot *externalapi.DomainHash) IsAnythingStaged() bool ReachabilityData(dbContext DBReader, blockHash *externalapi.DomainHash) (*ReachabilityData, error) + HasReachabilityData(dbContext DBReader, blockHash *externalapi.DomainHash) (bool, error) ReachabilityReindexRoot(dbContext DBReader) (*externalapi.DomainHash, error) } diff --git a/domain/consensus/processes/blockprocessor/validateandinsertblock.go b/domain/consensus/processes/blockprocessor/validateandinsertblock.go index 1f10ee785..f94353538 100644 --- a/domain/consensus/processes/blockprocessor/validateandinsertblock.go +++ b/domain/consensus/processes/blockprocessor/validateandinsertblock.go @@ -58,11 +58,6 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) if err != nil { return err } - - err = bp.headerTipsManager.AddHeaderTip(hash) - if err != nil { - return err - } } if mode.State == externalapi.SyncStateHeadersFirst { @@ -78,12 +73,21 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) return err } - oldHeadersSelectedTip, err := bp.headerTipsManager.SelectedTip() + hasTips, err := bp.headerTipsStore.HasTips(bp.databaseContext) if err != nil { return err } - if mode.State == externalapi.SyncStateHeadersFirst { + var oldHeadersSelectedTip *externalapi.DomainHash + if hasTips { + var err error + oldHeadersSelectedTip, err = bp.headerTipsManager.SelectedTip() + if err != nil { + return err + } + } + + if mode.State == externalapi.SyncStateHeadersFirst || mode.State == externalapi.SyncStateMissingGenesis { err = bp.headerTipsManager.AddHeaderTip(hash) if err != nil { return err @@ -102,21 +106,26 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) bp.headerTipsStore.Stage(tips) } - err = bp.updateReachabilityReindexRoot(oldHeadersSelectedTip) - if err != nil { - return err + if mode.State != externalapi.SyncStateMissingGenesis { + err = bp.updateReachabilityReindexRoot(oldHeadersSelectedTip) + if err != nil { + return err + } } - // Trigger pruning, which will check if the pruning point changed and delete the data if it did. - err = bp.pruningManager.FindNextPruningPoint() - if err != nil { - return err + if mode.State == externalapi.SyncStateNormal { + // Trigger pruning, which will check if the pruning point changed and delete the data if it did. + err = bp.pruningManager.FindNextPruningPoint() + if err != nil { + return err + } } return bp.commitAllChanges() } func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *externalapi.DomainHash) error { + headersSelectedTip, err := bp.headerTipsManager.SelectedTip() if err != nil { return err @@ -156,15 +165,28 @@ func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode *e } func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode *externalapi.SyncInfo) error { - // If any validation until (included) proof-of-work fails, simply - // return an error without writing anything in the database. - // This is to prevent spamming attacks. - err := bp.validatePreProofOfWork(block) + blockHash := consensusserialization.HeaderHash(block.Header) + hasHeader, err := bp.hasHeader(blockHash) + if err != nil { + return err + } + + if !hasHeader { + bp.blockHeaderStore.Stage(blockHash, block.Header) + err = bp.dagTopologyManager.SetParents(blockHash, block.Header.ParentHashes) + if err != nil { + return err + } + } + + // If any validation until (included) proof-of-work fails, simply + // return an error without writing anything in the database. + // This is to prevent spamming attacks. + err = bp.validatePreProofOfWork(block) if err != nil { return err } - blockHash := consensusserialization.BlockHash(block) err = bp.blockValidator.ValidateProofOfWorkAndDifficulty(blockHash) if err != nil { return err @@ -224,12 +246,6 @@ func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock } if !hasHeader { - bp.blockHeaderStore.Stage(blockHash, block.Header) - - err := bp.dagTopologyManager.SetParents(blockHash, block.Header.ParentHashes) - if err != nil { - return err - } err = bp.blockValidator.ValidateHeaderInContext(blockHash) if err != nil { return err diff --git a/domain/consensus/processes/blockvalidator/block_header_in_context.go b/domain/consensus/processes/blockvalidator/block_header_in_context.go index b3f006667..3db9baae9 100644 --- a/domain/consensus/processes/blockvalidator/block_header_in_context.go +++ b/domain/consensus/processes/blockvalidator/block_header_in_context.go @@ -26,12 +26,12 @@ func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHa return err } - status, err := v.blockStatusStore.Get(v.databaseContext, blockHash) + isHeadersOnlyBlock, err := v.isHeadersOnlyBlock(blockHash) if err != nil { return err } - if status != externalapi.StatusHeaderOnly { + if !isHeadersOnlyBlock { err = v.ghostdagManager.GHOSTDAG(blockHash) if err != nil { return err @@ -51,6 +51,24 @@ func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHa return nil } +func (v *blockValidator) isHeadersOnlyBlock(blockHash *externalapi.DomainHash) (bool, error) { + exists, err := v.blockStatusStore.Exists(v.databaseContext, blockHash) + if err != nil { + return false, err + } + + if !exists { + return false, nil + } + + status, err := v.blockStatusStore.Get(v.databaseContext, blockHash) + if err != nil { + return false, err + } + + return status == externalapi.StatusHeaderOnly, nil +} + // checkParentsIncest validates that no parent is an ancestor of another parent func (v *blockValidator) checkParentsIncest(header *externalapi.DomainBlockHeader) error { for _, parentA := range header.ParentHashes { diff --git a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go index 613515933..e354fa60c 100644 --- a/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go +++ b/domain/consensus/processes/dagtopologymanager/dagtopologymanager.go @@ -103,14 +103,22 @@ func isHashInSlice(hash *externalapi.DomainHash, hashes []*externalapi.DomainHas } func (dtm *dagTopologyManager) SetParents(blockHash *externalapi.DomainHash, parentHashes []*externalapi.DomainHash) error { - // Go over the block's current relations (if they exist), and remove the block from all it's current parents - // Note: In theory we should also remove the block from all it's children, however, in practice no block - // ever has it's relations updated after getting any children, therefore we skip this step - currentRelations, err := dtm.blockRelationStore.BlockRelation(dtm.databaseContext, blockHash) + + hasRelations, err := dtm.blockRelationStore.Has(dtm.databaseContext, blockHash) if err != nil { return err } - if currentRelations != nil { + + if hasRelations { + // Go over the block's current relations (if they exist), and remove the block from all its current parents + // Note: In theory we should also remove the block from all its children, however, in practice no block + // ever has its relations updated after getting any children, therefore we skip this step + + currentRelations, err := dtm.blockRelationStore.BlockRelation(dtm.databaseContext, blockHash) + if err != nil { + return err + } + for _, currentParent := range currentRelations.Parents { parentRelations, err := dtm.blockRelationStore.BlockRelation(dtm.databaseContext, currentParent) if err != nil { diff --git a/domain/consensus/processes/ghostdagmanager/ghostdag.go b/domain/consensus/processes/ghostdagmanager/ghostdag.go index 029f4d605..e1700331f 100644 --- a/domain/consensus/processes/ghostdagmanager/ghostdag.go +++ b/domain/consensus/processes/ghostdagmanager/ghostdag.go @@ -35,14 +35,18 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { if err != nil { return err } - selectedParent, err := gm.findSelectedParent(blockParents) - if err != nil { - return err - } - newBlockData.SelectedParent = selectedParent - newBlockData.MergeSetBlues = append(newBlockData.MergeSetBlues, selectedParent) - newBlockData.BluesAnticoneSizes[*selectedParent] = 0 + isGenesis := len(blockParents) == 0 + if !isGenesis { + selectedParent, err := gm.findSelectedParent(blockParents) + if err != nil { + return err + } + + newBlockData.SelectedParent = selectedParent + newBlockData.MergeSetBlues = append(newBlockData.MergeSetBlues, selectedParent) + newBlockData.BluesAnticoneSizes[*selectedParent] = 0 + } mergeSetWithoutSelectedParent, err := gm.mergeSetWithoutSelectedParent(newBlockData.SelectedParent, blockParents) if err != nil { @@ -67,11 +71,16 @@ func (gm *ghostdagManager) GHOSTDAG(blockHash *externalapi.DomainHash) error { } } - selectedParentGHOSTDAGData, err := gm.ghostdagDataStore.Get(gm.databaseContext, newBlockData.SelectedParent) - if err != nil { - return err + if !isGenesis { + selectedParentGHOSTDAGData, err := gm.ghostdagDataStore.Get(gm.databaseContext, newBlockData.SelectedParent) + if err != nil { + return err + } + newBlockData.BlueScore = selectedParentGHOSTDAGData.BlueScore + uint64(len(newBlockData.MergeSetBlues)) + } else { + // Genesis's blue score is defined to be 0. + newBlockData.BlueScore = 0 } - newBlockData.BlueScore = selectedParentGHOSTDAGData.BlueScore + uint64(len(newBlockData.MergeSetBlues)) gm.ghostdagDataStore.Stage(blockHash, newBlockData) return nil diff --git a/domain/consensus/processes/headertipsmanager/headertipsmanager.go b/domain/consensus/processes/headertipsmanager/headertipsmanager.go index cc0ed7f21..c271de7a3 100644 --- a/domain/consensus/processes/headertipsmanager/headertipsmanager.go +++ b/domain/consensus/processes/headertipsmanager/headertipsmanager.go @@ -26,11 +26,20 @@ func New(databaseContext model.DBReader, } func (h headerTipsManager) AddHeaderTip(hash *externalapi.DomainHash) error { - tips, err := h.headerTipsStore.Tips(h.databaseContext) + tips := []*externalapi.DomainHash{} + hasTips, err := h.headerTipsStore.HasTips(h.databaseContext) if err != nil { return err } + if hasTips { + var err error + tips, err = h.headerTipsStore.Tips(h.databaseContext) + if err != nil { + return err + } + } + newTips := make([]*externalapi.DomainHash, 0, len(tips)+1) for _, tip := range tips { isAncestorOf, err := h.dagTopologyManager.IsAncestorOf(tip, hash) diff --git a/domain/consensus/processes/headertipsmanager/selected_tip.go b/domain/consensus/processes/headertipsmanager/selected_tip.go index 72629c57f..a2d28f3df 100644 --- a/domain/consensus/processes/headertipsmanager/selected_tip.go +++ b/domain/consensus/processes/headertipsmanager/selected_tip.go @@ -8,5 +8,10 @@ func (h headerTipsManager) SelectedTip() (*externalapi.DomainHash, error) { return nil, err } - return h.ghostdagManager.ChooseSelectedParent(tips...) + selectedTip, err := h.ghostdagManager.ChooseSelectedParent(tips...) + if err != nil { + return nil, err + } + + return selectedTip, nil } diff --git a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go index 854e2a58c..41419ade6 100644 --- a/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go +++ b/domain/consensus/processes/mergedepthmanager/merge_depth_manager.go @@ -45,6 +45,11 @@ func (mdm *mergeDepthManager) CheckBoundedMergeDepth(blockHash *externalapi.Doma return err } + // Return nil on genesis + if ghostdagData.SelectedParent == nil { + return nil + } + finalityPoint, err := mdm.finalityPoint(ghostdagData) if err != nil { return err diff --git a/domain/consensus/processes/reachabilitymanager/fetch.go b/domain/consensus/processes/reachabilitymanager/fetch.go index d3196c3e9..9805a4e35 100644 --- a/domain/consensus/processes/reachabilitymanager/fetch.go +++ b/domain/consensus/processes/reachabilitymanager/fetch.go @@ -6,6 +6,18 @@ import ( ) func (rt *reachabilityManager) data(blockHash *externalapi.DomainHash) (*model.ReachabilityData, error) { + hasData, err := rt.reachabilityDataStore.HasReachabilityData(rt.databaseContext, blockHash) + if err != nil { + return nil, err + } + + if !hasData { + return &model.ReachabilityData{ + TreeNode: nil, + FutureCoveringSet: nil, + }, nil + } + return rt.reachabilityDataStore.ReachabilityData(rt.databaseContext, blockHash) } diff --git a/domain/consensus/processes/reachabilitymanager/tree.go b/domain/consensus/processes/reachabilitymanager/tree.go index 57286d798..16975f398 100644 --- a/domain/consensus/processes/reachabilitymanager/tree.go +++ b/domain/consensus/processes/reachabilitymanager/tree.go @@ -825,7 +825,7 @@ func (rt *reachabilityManager) findAncestorOfThisAmongChildrenOfOther(this, othe ancestor, ok := rt.findAncestorOfNode(otherChildren, this) if !ok { - return nil, errors.Errorf("node is not an ancestor of node") + return nil, errors.Errorf("node is not an ancestor of this") } return ancestor, nil diff --git a/domain/consensus/processes/syncmanager/syncinfo.go b/domain/consensus/processes/syncmanager/syncinfo.go index 7215370a3..85547a4b9 100644 --- a/domain/consensus/processes/syncmanager/syncinfo.go +++ b/domain/consensus/processes/syncmanager/syncinfo.go @@ -32,6 +32,15 @@ func (sm *syncManager) syncInfo() (*externalapi.SyncInfo, error) { } func (sm *syncManager) resolveSyncState() (externalapi.SyncState, error) { + hasTips, err := sm.headerTipsStore.HasTips(sm.databaseContext) + if err != nil { + return 0, err + } + + if !hasTips { + return externalapi.SyncStateMissingGenesis, nil + } + headerVirtualSelectedParentHash, err := sm.headerVirtualSelectedParentHash() if err != nil { return 0, err diff --git a/domain/consensus/utils/consensusserialization/block.go b/domain/consensus/utils/consensusserialization/block.go index 466f932d3..bec976620 100644 --- a/domain/consensus/utils/consensusserialization/block.go +++ b/domain/consensus/utils/consensusserialization/block.go @@ -41,5 +41,6 @@ func serializeHeader(w io.Writer, header *externalapi.DomainBlockHeader) error { return err } } - return writeElements(w, header.HashMerkleRoot, header.AcceptedIDMerkleRoot, header.UTXOCommitment, timestamp, header.Bits, header.Nonce) + return writeElements(w, &header.HashMerkleRoot, &header.AcceptedIDMerkleRoot, &header.UTXOCommitment, timestamp, + header.Bits, header.Nonce) } diff --git a/domain/consensus/utils/transactionhelper/new.go b/domain/consensus/utils/transactionhelper/new.go new file mode 100644 index 000000000..2c42bd035 --- /dev/null +++ b/domain/consensus/utils/transactionhelper/new.go @@ -0,0 +1,26 @@ +package transactionhelper + +import ( + "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" + "github.com/kaspanet/kaspad/domain/consensus/utils/hashes" +) + +// NewSubnetworkTransaction returns a new trsnactions in the specified subnetwork with specified gas and payload +func NewSubnetworkTransaction(version int32, inputs []*externalapi.DomainTransactionInput, + outputs []*externalapi.DomainTransactionOutput, subnetworkID *externalapi.DomainSubnetworkID, + gas uint64, payload []byte) *externalapi.DomainTransaction { + + payloadHash := hashes.HashData(payload) + return &externalapi.DomainTransaction{ + Version: version, + Inputs: inputs, + Outputs: outputs, + LockTime: 0, + SubnetworkID: *subnetworkID, + Gas: gas, + PayloadHash: *payloadHash, + Payload: payload, + Fee: 0, + Mass: 0, + } +} diff --git a/domain/dagconfig/genesis.go b/domain/dagconfig/genesis.go index b790babf1..9190ba4f0 100644 --- a/domain/dagconfig/genesis.go +++ b/domain/dagconfig/genesis.go @@ -5,13 +5,12 @@ package dagconfig import ( - "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" "github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks" - "github.com/kaspanet/kaspad/util/mstime" + "github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper" ) -var genesisTxOuts = []*appmessage.TxOut{} +var genesisTxOuts = []*externalapi.DomainTransactionOutput{} var genesisTxPayload = []byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Blue score @@ -23,16 +22,16 @@ var genesisTxPayload = []byte{ // genesisCoinbaseTx is the coinbase transaction for the genesis blocks for // the main network. -var genesisCoinbaseTx = appmessage.NewSubnetworkMsgTx(1, []*appmessage.TxIn{}, genesisTxOuts, +var genesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, []*externalapi.DomainTransactionInput{}, genesisTxOuts, &subnetworks.SubnetworkIDCoinbase, 0, genesisTxPayload) // genesisHash is the hash of the first block in the block DAG for the main // network (genesis block). var genesisHash = externalapi.DomainHash{ - 0x67, 0x8b, 0x44, 0x41, 0x59, 0xe5, 0x99, 0xe0, - 0x8e, 0x01, 0xad, 0x77, 0xce, 0x8b, 0x18, 0xe7, - 0x1f, 0x61, 0x8c, 0x7d, 0x0c, 0x2f, 0x98, 0xbe, - 0x63, 0xf4, 0x13, 0x89, 0x41, 0xc6, 0xdb, 0x9b, + 0x37, 0xf9, 0x09, 0x98, 0x0e, 0x12, 0xf6, 0xa2, + 0xaa, 0x0d, 0x09, 0xfa, 0x41, 0xad, 0x95, 0x1a, + 0x5b, 0x38, 0x14, 0x12, 0xe9, 0x02, 0x14, 0xcd, + 0xba, 0x64, 0xf6, 0x84, 0x72, 0xc4, 0xa4, 0x3a, } // genesisMerkleRoot is the hash of the first transaction in the genesis block @@ -46,21 +45,21 @@ var genesisMerkleRoot = externalapi.DomainHash{ // genesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for the main network. -var genesisBlock = appmessage.MsgBlock{ - Header: appmessage.BlockHeader{ - Version: 0x10000000, +var genesisBlock = externalapi.DomainBlock{ + Header: &externalapi.DomainBlockHeader{ + Version: 1, ParentHashes: []*externalapi.DomainHash{}, - HashMerkleRoot: &genesisMerkleRoot, - AcceptedIDMerkleRoot: &externalapi.DomainHash{}, - UTXOCommitment: &externalapi.DomainHash{}, - Timestamp: mstime.UnixMilliseconds(0x1730a81bdb4), + HashMerkleRoot: genesisMerkleRoot, + AcceptedIDMerkleRoot: externalapi.DomainHash{}, + UTXOCommitment: externalapi.DomainHash{}, + TimeInMilliseconds: 0x1730a81bdb4, Bits: 0x207fffff, Nonce: 0x1, }, - Transactions: []*appmessage.MsgTx{genesisCoinbaseTx}, + Transactions: []*externalapi.DomainTransaction{genesisCoinbaseTx}, } -var devnetGenesisTxOuts = []*appmessage.TxOut{} +var devnetGenesisTxOuts = []*externalapi.DomainTransactionOutput{} var devnetGenesisTxPayload = []byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Blue score @@ -73,44 +72,45 @@ var devnetGenesisTxPayload = []byte{ // devnetGenesisCoinbaseTx is the coinbase transaction for the genesis blocks for // the development network. -var devnetGenesisCoinbaseTx = appmessage.NewSubnetworkMsgTx(1, []*appmessage.TxIn{}, devnetGenesisTxOuts, +var devnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, + []*externalapi.DomainTransactionInput{}, devnetGenesisTxOuts, &subnetworks.SubnetworkIDCoinbase, 0, devnetGenesisTxPayload) // devGenesisHash is the hash of the first block in the block DAG for the development // network (genesis block). var devnetGenesisHash = externalapi.DomainHash{ - 0x3e, 0x0f, 0xb1, 0x20, 0x3b, 0xa1, 0x6f, 0xc5, - 0x92, 0x63, 0x67, 0x09, 0x76, 0x38, 0x35, 0xea, - 0x30, 0x89, 0xe6, 0x3a, 0x63, 0xe9, 0xf9, 0x6e, - 0x31, 0x0a, 0x54, 0xb7, 0x24, 0x02, 0xd0, 0xec, + 0xd3, 0xad, 0xd6, 0xe4, 0x6b, 0xc2, 0x33, 0xa9, + 0x20, 0x03, 0x1e, 0xf3, 0xe6, 0x8a, 0xf4, 0x08, + 0x91, 0xa1, 0x25, 0xc7, 0xc1, 0xf1, 0x5b, 0x3e, + 0x74, 0x72, 0xb5, 0x8a, 0xa0, 0x10, 0x00, 0x00, } // devnetGenesisMerkleRoot is the hash of the first transaction in the genesis block // for the devopment network. var devnetGenesisMerkleRoot = externalapi.DomainHash{ - 0x68, 0x60, 0xe7, 0x77, 0x47, 0x74, 0x7f, 0xd5, - 0x55, 0x58, 0x8a, 0xb5, 0xc2, 0x29, 0x0c, 0xa6, - 0x65, 0x44, 0xb4, 0x4f, 0xfa, 0x31, 0x7a, 0xfa, - 0x55, 0xe0, 0xcf, 0xac, 0x9c, 0x86, 0x30, 0x2a, + 0x00, 0x94, 0xfd, 0xff, 0x4d, 0xb2, 0x4d, 0x18, + 0x95, 0x21, 0x36, 0x2a, 0x14, 0xfb, 0x19, 0x7a, + 0x99, 0x51, 0x7e, 0x3f, 0x44, 0xf6, 0x2e, 0x0b, + 0xe7, 0xb3, 0xc0, 0xbb, 0x00, 0x3b, 0x0b, 0xbd, } // devnetGenesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for the development network. -var devnetGenesisBlock = appmessage.MsgBlock{ - Header: appmessage.BlockHeader{ - Version: 0x10000000, +var devnetGenesisBlock = externalapi.DomainBlock{ + Header: &externalapi.DomainBlockHeader{ + Version: 1, ParentHashes: []*externalapi.DomainHash{}, - HashMerkleRoot: &devnetGenesisMerkleRoot, - AcceptedIDMerkleRoot: &externalapi.DomainHash{}, - UTXOCommitment: &externalapi.DomainHash{}, - Timestamp: mstime.UnixMilliseconds(0x17305b05694), + HashMerkleRoot: devnetGenesisMerkleRoot, + AcceptedIDMerkleRoot: externalapi.DomainHash{}, + UTXOCommitment: externalapi.DomainHash{}, + TimeInMilliseconds: 0x17305b05694, Bits: 0x1e7fffff, - Nonce: 0x10bb, + Nonce: 282366, }, - Transactions: []*appmessage.MsgTx{devnetGenesisCoinbaseTx}, + Transactions: []*externalapi.DomainTransaction{devnetGenesisCoinbaseTx}, } -var simnetGenesisTxOuts = []*appmessage.TxOut{} +var simnetGenesisTxOuts = []*externalapi.DomainTransactionOutput{} var simnetGenesisTxPayload = []byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Blue score @@ -122,16 +122,17 @@ var simnetGenesisTxPayload = []byte{ } // simnetGenesisCoinbaseTx is the coinbase transaction for the simnet genesis block. -var simnetGenesisCoinbaseTx = appmessage.NewSubnetworkMsgTx(1, []*appmessage.TxIn{}, simnetGenesisTxOuts, +var simnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, + []*externalapi.DomainTransactionInput{}, simnetGenesisTxOuts, &subnetworks.SubnetworkIDCoinbase, 0, simnetGenesisTxPayload) // simnetGenesisHash is the hash of the first block in the block DAG for // the simnet (genesis block). var simnetGenesisHash = externalapi.DomainHash{ - 0x9d, 0x89, 0xb0, 0x6e, 0xb3, 0x47, 0xb5, 0x6e, - 0xcd, 0x6c, 0x63, 0x99, 0x45, 0x91, 0xd5, 0xce, - 0x9b, 0x43, 0x05, 0xc1, 0xa5, 0x5e, 0x2a, 0xda, - 0x90, 0x4c, 0xf0, 0x6c, 0x4d, 0x5f, 0xd3, 0x62, + 0xad, 0x47, 0xba, 0xd5, 0x6e, 0x1e, 0x62, 0x99, + 0x43, 0x81, 0xd2, 0xaf, 0xda, 0x1d, 0xe6, 0xda, + 0x0b, 0x50, 0xcb, 0x76, 0x8e, 0x5d, 0x9e, 0x41, + 0x20, 0x98, 0x28, 0xb1, 0x7e, 0x88, 0xb9, 0xb5, } // simnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -145,21 +146,21 @@ var simnetGenesisMerkleRoot = externalapi.DomainHash{ // simnetGenesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for the development network. -var simnetGenesisBlock = appmessage.MsgBlock{ - Header: appmessage.BlockHeader{ - Version: 0x10000000, +var simnetGenesisBlock = externalapi.DomainBlock{ + Header: &externalapi.DomainBlockHeader{ + Version: 1, ParentHashes: []*externalapi.DomainHash{}, - HashMerkleRoot: &simnetGenesisMerkleRoot, - AcceptedIDMerkleRoot: &externalapi.DomainHash{}, - UTXOCommitment: &externalapi.DomainHash{}, - Timestamp: mstime.UnixMilliseconds(0x173001df3d5), + HashMerkleRoot: simnetGenesisMerkleRoot, + AcceptedIDMerkleRoot: externalapi.DomainHash{}, + UTXOCommitment: externalapi.DomainHash{}, + TimeInMilliseconds: 0x173001df3d5, Bits: 0x207fffff, Nonce: 0x0, }, - Transactions: []*appmessage.MsgTx{simnetGenesisCoinbaseTx}, + Transactions: []*externalapi.DomainTransaction{simnetGenesisCoinbaseTx}, } -var testnetGenesisTxOuts = []*appmessage.TxOut{} +var testnetGenesisTxOuts = []*externalapi.DomainTransactionOutput{} var testnetGenesisTxPayload = []byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Blue score @@ -169,16 +170,17 @@ var testnetGenesisTxPayload = []byte{ } // testnetGenesisCoinbaseTx is the coinbase transaction for the testnet genesis block. -var testnetGenesisCoinbaseTx = appmessage.NewSubnetworkMsgTx(1, []*appmessage.TxIn{}, testnetGenesisTxOuts, +var testnetGenesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(1, + []*externalapi.DomainTransactionInput{}, testnetGenesisTxOuts, &subnetworks.SubnetworkIDCoinbase, 0, testnetGenesisTxPayload) // testnetGenesisHash is the hash of the first block in the block DAG for the test // network (genesis block). var testnetGenesisHash = externalapi.DomainHash{ - 0x91, 0xe2, 0x7f, 0x78, 0x4e, 0xe5, 0xf9, 0x3c, - 0xff, 0x58, 0x45, 0xc3, 0xa6, 0x1f, 0x03, 0x80, - 0x55, 0xbe, 0xf4, 0xf2, 0xd6, 0xdd, 0xe3, 0x38, - 0xb7, 0xac, 0xd6, 0x3d, 0xc5, 0xb7, 0x1c, 0x73, + 0x29, 0x0c, 0x43, 0x42, 0x66, 0x2d, 0x1b, 0x05, + 0x0b, 0xc7, 0xb2, 0x26, 0x8d, 0x53, 0x16, 0xbf, + 0x5a, 0x2d, 0x7e, 0xff, 0xee, 0x06, 0xb7, 0x2b, + 0x41, 0x9f, 0xe8, 0xf0, 0xfa, 0xc7, 0xd1, 0x1a, } // testnetGenesisMerkleRoot is the hash of the first transaction in the genesis block @@ -192,16 +194,16 @@ var testnetGenesisMerkleRoot = externalapi.DomainHash{ // testnetGenesisBlock defines the genesis block of the block DAG which serves as the // public transaction ledger for testnet. -var testnetGenesisBlock = appmessage.MsgBlock{ - Header: appmessage.BlockHeader{ - Version: 0x10000000, +var testnetGenesisBlock = externalapi.DomainBlock{ + Header: &externalapi.DomainBlockHeader{ + Version: 1, ParentHashes: []*externalapi.DomainHash{}, - HashMerkleRoot: &testnetGenesisMerkleRoot, - AcceptedIDMerkleRoot: &externalapi.DomainHash{}, - UTXOCommitment: &externalapi.DomainHash{}, - Timestamp: mstime.UnixMilliseconds(0x1730a66a9d9), + HashMerkleRoot: testnetGenesisMerkleRoot, + AcceptedIDMerkleRoot: externalapi.DomainHash{}, + UTXOCommitment: externalapi.DomainHash{}, + TimeInMilliseconds: 0x1730a66a9d9, Bits: 0x1e7fffff, Nonce: 0x162ca, }, - Transactions: []*appmessage.MsgTx{testnetGenesisCoinbaseTx}, + Transactions: []*externalapi.DomainTransaction{testnetGenesisCoinbaseTx}, } diff --git a/domain/dagconfig/genesis_test.go b/domain/dagconfig/genesis_test.go index faf0a6648..5c8607df3 100644 --- a/domain/dagconfig/genesis_test.go +++ b/domain/dagconfig/genesis_test.go @@ -7,21 +7,17 @@ package dagconfig import ( "testing" - "github.com/kaspanet/kaspad/app/appmessage" "github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization" - - "github.com/davecgh/go-spew/spew" ) // TestGenesisBlock tests the genesis block of the main network for validity by // checking the encoded hash. func TestGenesisBlock(t *testing.T) { // Check hash of the block against expected hash. - hash := consensusserialization.BlockHash(appmessage.MsgBlockToDomainBlock(MainnetParams.GenesisBlock)) + hash := consensusserialization.BlockHash(MainnetParams.GenesisBlock) if *MainnetParams.GenesisHash != *hash { t.Fatalf("TestGenesisBlock: Genesis block hash does "+ - "not appear valid - got %v, want %v", spew.Sdump(hash), - spew.Sdump(MainnetParams.GenesisHash)) + "not appear valid - got %v, want %v", hash, MainnetParams.GenesisHash) } } @@ -29,11 +25,11 @@ func TestGenesisBlock(t *testing.T) { // validity by checking the hash. func TestTestnetGenesisBlock(t *testing.T) { // Check hash of the block against expected hash. - hash := consensusserialization.BlockHash(appmessage.MsgBlockToDomainBlock(TestnetParams.GenesisBlock)) + hash := consensusserialization.BlockHash(TestnetParams.GenesisBlock) if *TestnetParams.GenesisHash != *hash { t.Fatalf("TestTestnetGenesisBlock: Genesis block hash does "+ - "not appear valid - got %v, want %v", spew.Sdump(hash), - spew.Sdump(TestnetParams.GenesisHash)) + "not appear valid - got %v, want %v", hash, + TestnetParams.GenesisHash) } } @@ -41,11 +37,11 @@ func TestTestnetGenesisBlock(t *testing.T) { // for validity by checking the hash. func TestSimnetGenesisBlock(t *testing.T) { // Check hash of the block against expected hash. - hash := consensusserialization.BlockHash(appmessage.MsgBlockToDomainBlock(SimnetParams.GenesisBlock)) + hash := consensusserialization.BlockHash(SimnetParams.GenesisBlock) if *SimnetParams.GenesisHash != *hash { t.Fatalf("TestSimnetGenesisBlock: Genesis block hash does "+ - "not appear valid - got %v, want %v", spew.Sdump(hash), - spew.Sdump(SimnetParams.GenesisHash)) + "not appear valid - got %v, want %v", hash, + SimnetParams.GenesisHash) } } @@ -53,10 +49,10 @@ func TestSimnetGenesisBlock(t *testing.T) { // for validity by checking the encoded hash. func TestDevnetGenesisBlock(t *testing.T) { // Check hash of the block against expected hash. - hash := consensusserialization.BlockHash(appmessage.MsgBlockToDomainBlock(DevnetParams.GenesisBlock)) + hash := consensusserialization.BlockHash(DevnetParams.GenesisBlock) if *DevnetParams.GenesisHash != *hash { t.Fatalf("TestDevnetGenesisBlock: Genesis block hash does "+ - "not appear valid - got %v, want %v", spew.Sdump(hash), - spew.Sdump(DevnetParams.GenesisHash)) + "not appear valid - got %v, want %v", hash, + DevnetParams.GenesisHash) } } diff --git a/domain/dagconfig/params.go b/domain/dagconfig/params.go index 758ebabef..aeefbee5a 100644 --- a/domain/dagconfig/params.go +++ b/domain/dagconfig/params.go @@ -80,7 +80,7 @@ type Params struct { DNSSeeds []string // GenesisBlock defines the first block of the DAG. - GenesisBlock *appmessage.MsgBlock + GenesisBlock *externalapi.DomainBlock // GenesisHash is the starting block hash. GenesisHash *externalapi.DomainHash