Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warpsync: epoch syncing #2367

Merged
merged 68 commits into from
Aug 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
ed9f0ba
Remove prints
karimodm Jul 12, 2022
7e51c1b
WIP: initial split
karimodm Jul 12, 2022
b329387
Compiles
karimodm Jul 13, 2022
1c43f2a
Split gossip / p2p working
karimodm Jul 13, 2022
5d9a542
Fixed unit tests
karimodm Jul 13, 2022
f68b850
Comments
karimodm Jul 13, 2022
37a4b3a
Fix: integration tests
karimodm Jul 13, 2022
6096062
Merge remote-tracking branch 'origin/develop' into refactor/p2p-gossi…
karimodm Jul 13, 2022
9fea4e8
Remove unused dependencies
karimodm Jul 13, 2022
debd400
rename variable
karimodm Jul 13, 2022
3550a76
New warpsync protobuf format
karimodm Jul 13, 2022
9550b59
Small fixes
karimodm Jul 14, 2022
bf4fae2
Fix: inbound stream negotiation
karimodm Jul 14, 2022
a59d31f
Update packages/p2p/neighbor.go
karimodm Jul 14, 2022
1a3a45c
Address review comments
karimodm Jul 14, 2022
0c32e97
Merge branch 'refactor/p2p-gossip-split' of github.com:iotaledger/gos…
karimodm Jul 14, 2022
71ad54b
hive.go version bump
karimodm Jul 14, 2022
2fdc019
Merge remote-tracking branch 'origin/develop' into refactor/p2p-gossi…
karimodm Jul 14, 2022
7fe4af2
go mod tidy
karimodm Jul 14, 2022
9e6de21
Merge branch 'refactor/p2p-gossip-split' into feat/epoch-syncing
karimodm Jul 14, 2022
e46cc3a
Merge remote-tracking branch 'origin/develop' into feat/epoch-syncing
karimodm Jul 14, 2022
e024881
Fix: protocol initialization
karimodm Jul 18, 2022
5f96247
confirmed -> accepted renaming in logs
karimodm Jul 18, 2022
2a8e3c4
WIP
karimodm Jul 19, 2022
2336cb8
proto changes
karimodm Jul 19, 2022
ababc03
ValidateBackwards
karimodm Jul 19, 2022
f28b84a
Merge remote-tracking branch 'origin/develop' into feat/epoch-syncing
karimodm Jul 19, 2022
bd7a21e
Basic Epoch Syncinc
karimodm Jul 20, 2022
1bf19a6
Syncing & Validation all packets processed
karimodm Jul 21, 2022
ab73035
Use getters in epochstorage
karimodm Jul 21, 2022
89abce3
Moved warpsync under packages/node/
karimodm Jul 21, 2022
8af50a6
warpsync plugin
karimodm Jul 21, 2022
7634059
Triggering of WarpSync on BlockStore
karimodm Jul 26, 2022
cb8b5c3
Fixed p2p protocol multiplexing
karimodm Jul 27, 2022
3422cb5
Store subRoots next to epoch Roots
karimodm Jul 27, 2022
1009f86
trivial validation & syncing WIP
karimodm Jul 27, 2022
223f485
Epoch syncing: validating backwards and forward
karimodm Jul 27, 2022
8968518
Disable Warpsync in integration tests
karimodm Jul 27, 2022
de11147
Use byteutils to concat bytes
karimodm Aug 3, 2022
dbf1988
Changed names of epochstorage methods
karimodm Aug 3, 2022
400e8fa
epochstorage keyiteration fix
karimodm Aug 3, 2022
c174b7a
block.FromBytes
karimodm Aug 3, 2022
5ccbf28
WIP
karimodm Aug 3, 2022
c212a18
Remove prints from epochstorage
karimodm Aug 3, 2022
c899145
syncing works
karimodm Aug 3, 2022
641275d
Address some review comments
karimodm Aug 4, 2022
e6aa622
Refactored Validation
karimodm Aug 8, 2022
6177665
Refactored Syncing using dataflows
karimodm Aug 9, 2022
849f080
Rewiring
karimodm Aug 9, 2022
1092433
Refactored Validation even more
karimodm Aug 9, 2022
51582a8
Remove unused var
karimodm Aug 9, 2022
7252a2a
Terminate sync loop across peers upon success
karimodm Aug 9, 2022
b7a8ac5
Unexport validation and syncing methods
karimodm Aug 10, 2022
96bb9b9
Merge remote-tracking branch 'origin/develop' into feat/epoch-syncing
karimodm Aug 10, 2022
23e4939
Fixes after merge
karimodm Aug 10, 2022
1e2b2b2
Use generics.Option
karimodm Aug 10, 2022
a1ea58f
Many many fixes
karimodm Aug 11, 2022
1eee490
Logging adjustments
karimodm Aug 12, 2022
6f30ebf
select return case first
karimodm Aug 15, 2022
0c7ff57
Call IsStopped only from exported function
karimodm Aug 16, 2022
1bbf0e8
Consider valid only active peers
karimodm Aug 21, 2022
c56f92e
Warpsyncing in sliding window
karimodm Aug 21, 2022
9ca42ad
Merge remote-tracking branch 'origin/develop' into feat/epoch-syncing
karimodm Aug 21, 2022
a150cf4
Readability changes
karimodm Aug 21, 2022
85c1703
Store output creation time
karimodm Aug 22, 2022
74ee41a
Merge remote-tracking branch 'origin/develop' into feat/epoch-syncing
karimodm Aug 22, 2022
103dbb0
Resolve errors after merge
karimodm Aug 22, 2022
b38b6a1
Increase WarpSync timeout to 5m
karimodm Aug 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@ proto: $(PROTO_GO_FILES)
# If $GOPATH/bin/protoc-gen-go does not exist, we'll run this command to install it.
$(PROTOC_GEN_GO):
go install google.golang.org/protobuf/cmd/protoc-gen-go
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc

# Implicit compile rule for GRPC/proto files
%.pb.go: %.proto | $(PROTOC_GEN_GO)
protoc $< --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:.
protoc $< --go_out=paths=source_relative:.

.PHONY: clean_proto
clean_proto:
Expand Down
2 changes: 1 addition & 1 deletion packages/core/consensus/acceptance/gadget.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const (

var (
// DefaultConflictTranslation is the default function to translate the approval weight to confirmation.State of a conflict.
DefaultConflictTranslation ConflictThresholdTranslation = func(conflictID utxo.TransactionID, aw float64) confirmation.State {
DefaultConflictTranslation ConflictThresholdTranslation = func(_ utxo.TransactionID, aw float64) confirmation.State {
if aw >= acceptanceThreshold {
return confirmation.Accepted
}
Expand Down
56 changes: 52 additions & 4 deletions packages/core/epoch/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
"time"

"github.com/iotaledger/hive.go/core/byteutils"
"github.com/iotaledger/hive.go/core/generics/model"
"github.com/iotaledger/hive.go/core/serix"
"github.com/mr-tron/base58"
Expand Down Expand Up @@ -78,7 +79,7 @@ type (
EC = MerkleRoot
)

func NewMerkleRoot(bytes []byte) (mr MerkleRoot) {
func NewMerkleRoot(bytes []byte) MerkleRoot {
b := [blake2b.Size256]byte{}
copy(b[:], bytes[:])
return b
Expand All @@ -92,15 +93,24 @@ func (m MerkleRoot) Bytes() []byte {
return m[:]
}

// CommitmentRoots contains roots of trees of an epoch.
type CommitmentRoots struct {
TangleRoot MerkleRoot `serix:"0"`
StateMutationRoot MerkleRoot `serix:"1"`
StateRoot MerkleRoot `serix:"2"`
ManaRoot MerkleRoot `serix:"3"`
}

// ECRecord is a storable object represents the ecRecord of an epoch.
type ECRecord struct {
model.Storable[Index, ECRecord, *ECRecord, ecRecord] `serix:"0"`
}

type ecRecord struct {
EI Index `serix:"0"`
ECR ECR `serix:"1"`
PrevEC EC `serix:"2"`
EI Index `serix:"0"`
ECR ECR `serix:"1"`
PrevEC EC `serix:"2"`
Roots *CommitmentRoots `serix:"3"`
}

// NewECRecord creates and returns a ECRecord of the given EI.
Expand All @@ -109,6 +119,7 @@ func NewECRecord(ei Index) (new *ECRecord) {
EI: ei,
ECR: MerkleRoot{},
PrevEC: MerkleRoot{},
Roots: &CommitmentRoots{},
})
new.SetID(ei)
return
Expand Down Expand Up @@ -177,6 +188,43 @@ func (e *ECRecord) FromBytes(bytes []byte) (err error) {
return
}

// Roots returns the CommitmentRoots of an ECRecord.
func (e *ECRecord) Roots() *CommitmentRoots {
e.RLock()
defer e.RUnlock()

return e.M.Roots
}

// SetRoots sets the CommitmentRoots of an ECRecord.
func (e *ECRecord) SetRoots(roots *CommitmentRoots) {
e.Lock()
defer e.Unlock()

e.M.Roots = roots
e.SetModified()
}

// ComputeEC calculates the epoch commitment hash from the given ECRecord.
func (e *ECRecord) ComputeEC() (ec EC) {
ecHash := blake2b.Sum256(byteutils.ConcatBytes(e.EI().Bytes(), e.ECR().Bytes(), e.PrevEC().Bytes()))

return NewMerkleRoot(ecHash[:])
}

// region hashing functions ////////////////////////////////////////////////////////////////////////////////////////////

// ComputeECR calculates an ECR from the tree roots.
func ComputeECR(tangleRoot, stateMutationRoot, stateRoot, manaRoot MerkleRoot) ECR {
branch1Hashed := blake2b.Sum256(byteutils.ConcatBytes(tangleRoot.Bytes(), stateMutationRoot.Bytes()))
branch2Hashed := blake2b.Sum256(byteutils.ConcatBytes(stateRoot.Bytes(), manaRoot.Bytes()))
rootHashed := blake2b.Sum256(byteutils.ConcatBytes(branch1Hashed[:], branch2Hashed[:]))

return NewMerkleRoot(rootHashed[:])
}

// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////

// region NodesActivityLog //////////////////////////////////////////////////////////////////////////////////////////////////

type NodesActivityLog map[Index]*ActivityLog
Expand Down
1 change: 1 addition & 0 deletions packages/core/ledger/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,7 @@ func NewOutputWithMetadata(outputID utxo.OutputID, output utxo.Output, creationT
new = model.NewStorable[utxo.OutputID, OutputWithMetadata](&outputWithMetadataModel{
OutputID: outputID,
Output: output,
CreationTime: creationTime,
ConsensusManaPledgeID: consensusManaPledgeID,
AccessManaPledgeID: accessManaPledgeID,
})
Expand Down
49 changes: 16 additions & 33 deletions packages/core/notarization/commitments.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package notarization

import (
"context"

"github.com/celestiaorg/smt"
"github.com/cockroachdb/errors"
"github.com/iotaledger/hive.go/core/byteutils"
"github.com/iotaledger/hive.go/core/identity"
"github.com/iotaledger/hive.go/core/serix"

Expand Down Expand Up @@ -93,20 +93,14 @@ func (f *EpochCommitmentFactory) ManaRoot() []byte {
return f.manaRootTree.Root()
}

// ECR retrieves the epoch commitment root.
func (f *EpochCommitmentFactory) ECR(ei epoch.Index) (ecr epoch.ECR, err error) {
epochRoots, err := f.newEpochRoots(ei)
// ECRandRoots retrieves the epoch commitment root.
func (f *EpochCommitmentFactory) ECRandRoots(ei epoch.Index) (ecr epoch.ECR, roots *epoch.CommitmentRoots, err error) {
roots, err = f.newEpochRoots(ei)
if err != nil {
return epoch.MerkleRoot{}, errors.Wrap(err, "ECR could not be created")
return epoch.MerkleRoot{}, nil, errors.Wrap(err, "ECR could not be created")
}

branch1aHashed := blake2b.Sum256(byteutils.ConcatBytes(epochRoots.tangleRoot[:], epochRoots.stateMutationRoot[:]))
branch1bHashed := blake2b.Sum256(byteutils.ConcatBytes(epochRoots.stateRoot[:], epochRoots.manaRoot[:]))
branch1Hashed := blake2b.Sum256(byteutils.ConcatBytes(branch1aHashed[:], branch1bHashed[:]))
branch2Hashed := blake2b.Sum256(epochRoots.activityRoot[:])
rootHashed := blake2b.Sum256(byteutils.ConcatBytes(branch1Hashed[:], branch2Hashed[:]))

return epoch.NewMerkleRoot(rootHashed[:]), nil
return epoch.ComputeECR(roots.TangleRoot, roots.StateMutationRoot, roots.StateRoot, roots.ManaRoot), roots, nil
}

// removeStateLeaf removes the output ID from the ledger sparse merkle tree.
Expand Down Expand Up @@ -218,7 +212,7 @@ func (f *EpochCommitmentFactory) ecRecord(ei epoch.Index) (ecRecord *epoch.ECRec
return ecRecord, nil
}
// We never committed this epoch before, create and roll to a new epoch.
ecr, ecrErr := f.ECR(ei)
ecr, roots, ecrErr := f.ECRandRoots(ei)
if ecrErr != nil {
return nil, ecrErr
}
Expand All @@ -230,7 +224,8 @@ func (f *EpochCommitmentFactory) ecRecord(ei epoch.Index) (ecRecord *epoch.ECRec
// Store and return.
f.storage.CachedECRecord(ei, epoch.NewECRecord).Consume(func(e *epoch.ECRecord) {
e.SetECR(ecr)
e.SetPrevEC(EC(prevECRecord))
e.SetRoots(roots)
e.SetPrevEC(prevECRecord.ComputeEC())
ecRecord = e
})

Expand All @@ -241,6 +236,7 @@ func (f *EpochCommitmentFactory) loadECRecord(ei epoch.Index) (ecRecord *epoch.E
f.storage.CachedECRecord(ei).Consume(func(record *epoch.ECRecord) {
ecRecord = epoch.NewECRecord(ei)
ecRecord.SetECR(record.ECR())
ecRecord.SetRoots(record.Roots())
ecRecord.SetPrevEC(record.PrevEC())
})
return
Expand Down Expand Up @@ -334,7 +330,7 @@ func (f *EpochCommitmentFactory) newCommitmentTrees(ei epoch.Index) *CommitmentT
}

// newEpochRoots creates a new commitment with the given ei, by advancing the corresponding data structures.
func (f *EpochCommitmentFactory) newEpochRoots(ei epoch.Index) (commitmentRoots *CommitmentRoots, commitmentTreesErr error) {
func (f *EpochCommitmentFactory) newEpochRoots(ei epoch.Index) (commitmentRoots *epoch.CommitmentRoots, commitmentTreesErr error) {
// TODO: what if a node restarts and we have incomplete trees?
commitmentTrees, commitmentTreesErr := f.getCommitmentTrees(ei)
if commitmentTreesErr != nil {
Expand All @@ -350,12 +346,11 @@ func (f *EpochCommitmentFactory) newEpochRoots(ei epoch.Index) (commitmentRoots
// We advance the LedgerState to the next epoch.
f.commitLedgerState(ei - epoch.Index(f.snapshotDepth))

commitmentRoots = &CommitmentRoots{
EI: ei,
stateRoot: epoch.NewMerkleRoot(stateRoot),
manaRoot: epoch.NewMerkleRoot(manaRoot),
tangleRoot: epoch.NewMerkleRoot(commitmentTrees.tangleTree.Root()),
stateMutationRoot: epoch.NewMerkleRoot(commitmentTrees.stateMutationTree.Root()),
commitmentRoots = &epoch.CommitmentRoots{
StateRoot: epoch.NewMerkleRoot(stateRoot),
ManaRoot: epoch.NewMerkleRoot(manaRoot),
TangleRoot: epoch.NewMerkleRoot(commitmentTrees.tangleTree.Root()),
StateMutationRoot: epoch.NewMerkleRoot(commitmentTrees.stateMutationTree.Root()),
}

// We are never going to use this epoch's commitment trees again.
Expand Down Expand Up @@ -431,18 +426,6 @@ func (f *EpochCommitmentFactory) newStateRoots(ei epoch.Index) (stateRoot []byte

// region extra functions //////////////////////////////////////////////////////////////////////////////////////////////

// EC calculates the epoch commitment hash from the given ECRecord.
func EC(ecRecord *epoch.ECRecord) (ec epoch.EC) {
concatenated := make([]byte, 0)
concatenated = append(concatenated, ecRecord.EI().Bytes()...)
concatenated = append(concatenated, ecRecord.ECR().Bytes()...)
concatenated = append(concatenated, ecRecord.PrevEC().Bytes()...)

ecHash := blake2b.Sum256(concatenated)

return epoch.NewMerkleRoot(ecHash[:])
}

// insertLeaf inserts the outputID to the provided sparse merkle tree.
func insertLeaf(tree *smt.SparseMerkleTree, keyBytes, valueBytes []byte) error {
_, err := tree.Update(keyBytes, valueBytes)
Expand Down
125 changes: 125 additions & 0 deletions packages/core/notarization/events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package notarization

import (
"github.com/iotaledger/goshimmer/packages/core/epoch"
"github.com/iotaledger/goshimmer/packages/core/ledger"
"github.com/iotaledger/goshimmer/packages/core/ledger/utxo"
"github.com/iotaledger/goshimmer/packages/core/tangleold"
"github.com/iotaledger/hive.go/core/generics/event"
"github.com/iotaledger/hive.go/core/identity"
)

// region Events ///////////////////////////////////////////////////////////////////////////////////////////////////////

// Events is a container that acts as a dictionary for the existing events of a notarization manager.
type Events struct {
// EpochCommittable is an event that gets triggered whenever an epoch commitment is committable.
EpochCommittable *event.Event[*EpochCommittableEvent]
// EpochConfirmed is an event that gets triggered whenever an epoch is confirmed.
EpochConfirmed *event.Event[*EpochConfirmedEvent]
// CompetingCommitmentDetected is an event that gets triggered whenever a competing epoch commitment is detected.
CompetingCommitmentDetected *event.Event[*CompetingCommitmentDetectedEvent]
// ManaVectorUpdate is an event that gets triggered whenever the consensus mana vector needs to be updated.
ManaVectorUpdate *event.Event[*ManaVectorUpdateEvent]
// TangleTreeInserted is an event that gets triggered when a Block is inserted into the Tangle smt.
TangleTreeInserted *event.Event[*TangleTreeUpdatedEvent]
// TangleTreeRemoved is an event that gets triggered when a Block is removed from Tangle smt.
TangleTreeRemoved *event.Event[*TangleTreeUpdatedEvent]
// StateMutationTreeInserted is an event that gets triggered when a transaction is inserted into the state mutation smt.
StateMutationTreeInserted *event.Event[*StateMutationTreeUpdatedEvent]
// StateMutationTreeRemoved is an event that gets triggered when a transaction is removed from state mutation smt.
StateMutationTreeRemoved *event.Event[*StateMutationTreeUpdatedEvent]
// UTXOTreeInserted is an event that gets triggered when UTXOs are stored into the UTXO smt.
UTXOTreeInserted *event.Event[*UTXOUpdatedEvent]
// UTXOTreeRemoved is an event that gets triggered when UTXOs are removed from the UTXO smt.
UTXOTreeRemoved *event.Event[*UTXOUpdatedEvent]
// Bootstrapped is an event that gets triggered when a notarization manager has the last committable epoch relatively close to current epoch.
Bootstrapped *event.Event[*BootstrappedEvent]
// SyncRange is an event that gets triggered when an entire range of epochs needs to be requested, validated and solidified
SyncRange *event.Event[*SyncRangeEvent]
// ActivityTreeInserted is an event that gets triggered when nodeID is added to the activity tree.
ActivityTreeInserted *event.Event[*ActivityTreeUpdatedEvent]
// ActivityTreeRemoved is an event that gets triggered when nodeID is removed from activity tree.
ActivityTreeRemoved *event.Event[*ActivityTreeUpdatedEvent]

}

// TangleTreeUpdatedEvent is a container that acts as a dictionary for the TangleTree inserted/removed event related parameters.
type TangleTreeUpdatedEvent struct {
// EI is the index of the block.
EI epoch.Index
// BlockID is the blockID that inserted/removed to/from the tangle smt.
BlockID tangleold.BlockID
}

// BootstrappedEvent is an event that gets triggered when a notarization manager has the last committable epoch relatively close to current epoch.
type BootstrappedEvent struct {
// EI is the index of the last commitable epoch
EI epoch.Index
}

// StateMutationTreeUpdatedEvent is a container that acts as a dictionary for the State mutation tree inserted/removed event related parameters.
type StateMutationTreeUpdatedEvent struct {
// EI is the index of the transaction.
EI epoch.Index
// TransactionID is the transaction ID that inserted/removed to/from the state mutation smt.
TransactionID utxo.TransactionID
}

// UTXOUpdatedEvent is a container that acts as a dictionary for the UTXO update event related parameters.
type UTXOUpdatedEvent struct {
// EI is the index of updated UTXO.
EI epoch.Index
// Created are the outputs created in a transaction.
Created []*ledger.OutputWithMetadata
// Spent are outputs that is spent in a transaction.
Spent []*ledger.OutputWithMetadata
}

// EpochCommittableEvent is a container that acts as a dictionary for the EpochCommittable event related parameters.
type EpochCommittableEvent struct {
// EI is the index of committable epoch.
EI epoch.Index
// ECRecord is the ec root of committable epoch.
ECRecord *epoch.ECRecord
}

// EpochConfirmedEvent is a container that acts as a dictionary for the EpochConfirmed event related parameters.
type EpochConfirmedEvent struct {
// EI is the index of committable epoch.
EI epoch.Index
}

// CompetingCommitmentDetectedEvent is a container that acts as a dictionary for the CompetingCommitmentDetectedEvent event related parameters.
type CompetingCommitmentDetectedEvent struct {
// Block is the block that contains the competing commitment.
Block *tangleold.Block
}

// ManaVectorUpdateEvent is a container that acts as a dictionary for the EpochCommittable event related parameters.
type ManaVectorUpdateEvent struct {
// EI is the index of committable epoch.
EI epoch.Index
// EpochDiffCreated is the list of outputs created in the epoch.
EpochDiffCreated []*ledger.OutputWithMetadata
// EpochDiffSpent is the list of outputs spent in the epoch.
EpochDiffSpent []*ledger.OutputWithMetadata
}

// SyncRangeEvent is a container that acts as a dictionary for the SyncRange event related parameters.
type SyncRangeEvent struct {
StartEI epoch.Index
EndEI epoch.Index
StartEC epoch.EC
EndPrevEC epoch.EC
}

// ActivityTreeUpdatedEvent is a container that acts as a dictionary for the ActivityTree inserted/removed event related parameters.
type ActivityTreeUpdatedEvent struct {
// EI is the index of the epoch.
EI epoch.Index
// NodeID is the issuer nodeID.
NodeID identity.ID
}

// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
Loading