Skip to content

Commit

Permalink
Add smeshing identities endpoint (based on #6266) add post, poet and …
Browse files Browse the repository at this point in the history
…atx states
  • Loading branch information
kacpersaw committed Nov 13, 2024
1 parent fac1e72 commit 7ec1727
Show file tree
Hide file tree
Showing 10 changed files with 448 additions and 57 deletions.
17 changes: 17 additions & 0 deletions activation/activation.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ type Builder struct {
// states of each known identity
postStates PostStates

// identity states of each known identity
identitiesStates IdentityStates

// smeshingMutex protects methods like `StartSmeshing` and `StopSmeshing` from concurrent execution
// since they (can) modify the fields below.
smeshingMutex sync.Mutex
Expand Down Expand Up @@ -158,6 +161,12 @@ func WithPostStates(ps PostStates) BuilderOption {
}
}

func WithIdentityStates(is IdentityStates) BuilderOption {
return func(b *Builder) {
b.identitiesStates = is
}
}

func BuilderAtxVersions(v AtxVersions) BuilderOption {
return func(h *Builder) {
h.versions = append([]atxVersion{{0, types.AtxV1}}, v.asSlice()...)
Expand Down Expand Up @@ -191,6 +200,7 @@ func NewBuilder(
logger: log,
poetRetryInterval: defaultPoetRetryInterval,
postStates: NewPostStates(log),
identitiesStates: NewIdentityStateStorage(),
versions: []atxVersion{{0, types.AtxV1}},
posAtxFinder: positioningAtxFinder{
logger: log,
Expand Down Expand Up @@ -498,6 +508,8 @@ func (b *Builder) run(ctx context.Context, sig *signing.EdSigner) {

func (b *Builder) BuildNIPostChallenge(ctx context.Context, nodeID types.NodeID) (*types.NIPostChallenge, error) {
logger := b.logger.With(log.ZShortStringer("smesherID", nodeID))
b.identitiesStates.Set(nodeID, nil, IdentityStateWaitForATXSyncing, "")

select {
case <-ctx.Done():
return nil, ctx.Err()
Expand Down Expand Up @@ -551,6 +563,7 @@ func (b *Builder) BuildNIPostChallenge(ctx context.Context, nodeID types.NodeID)
)
events.EmitPoetWaitRound(nodeID, currentEpochId, publishEpochId, wait)
events.EmitWaitingForPoETRegistrationWindow(nodeID, currentEpochId, publishEpochId, wait)
b.identitiesStates.Set(nodeID, &publishEpochId, IdentityStateWaitingForPoetRegistrationWindow, "")
select {
case <-ctx.Done():
return nil, ctx.Err()
Expand Down Expand Up @@ -715,6 +728,8 @@ func (b *Builder) PublishActivationTx(ctx context.Context, sig *signing.EdSigner
zap.Uint32("current_epoch", b.layerClock.CurrentLayer().GetEpoch().Uint32()),
zap.Object("challenge", challenge),
)
b.identitiesStates.Set(sig.NodeID(), &challenge.PublishEpoch, IdentityStatePoetChallengeReady, "")

targetEpoch := challenge.PublishEpoch.Add(1)
ctx, cancel := context.WithDeadline(ctx, b.layerClock.LayerToTime(targetEpoch.FirstLayer()))
defer cancel()
Expand All @@ -729,6 +744,7 @@ func (b *Builder) PublishActivationTx(ctx context.Context, sig *signing.EdSigner
zap.Uint32("current_layer", b.layerClock.CurrentLayer().Uint32()),
log.ZShortStringer("smesherID", sig.NodeID()),
)
b.identitiesStates.Set(sig.NodeID(), &challenge.PublishEpoch, IdentityStateATXReady, "")
select {
case <-ctx.Done():
return fmt.Errorf("wait for publication epoch: %w", ctx.Err())
Expand Down Expand Up @@ -774,6 +790,7 @@ func (b *Builder) PublishActivationTx(ctx context.Context, sig *signing.EdSigner
atx.ID(),
b.layerClock.LayerToTime(target.FirstLayer()),
)
b.identitiesStates.Set(sig.NodeID(), &challenge.PublishEpoch, IdentityStateATXBroadcasted, "")
return nil
}

Expand Down
197 changes: 197 additions & 0 deletions activation/identity_states.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
package activation

import (
"errors"
"fmt"
"sync"
"time"

"github.com/spacemeshos/go-spacemesh/common/types"
)

var (
ErrIdentityStateUnknown = errors.New("identity state is unknown")
ErrInvalidIdentityStateSwitch = errors.New("invalid identity state switch")
)

type IdentityState int

const (
IdentityStateNotSet IdentityState = iota

IdentityStateWaitForATXSyncing

// poet

Check failure on line 24 in activation/identity_states.go

View workflow job for this annotation

GitHub Actions / lint

Comment should end in a period (godot)
IdentityStateWaitingForPoetRegistrationWindow
// building nipost challenge

Check failure on line 26 in activation/identity_states.go

View workflow job for this annotation

GitHub Actions / lint

Comment should end in a period (godot)
IdentityStatePoetChallengeReady
IdentityStatePoetRegistered
IdentityStatePoetRegistrationFailed
// 2w pass ...
IdentityStateWaitForPoetRoundEnd
IdentityStatePoetProofReceived
IdentityStatePoetProofFailed

// post

Check failure on line 35 in activation/identity_states.go

View workflow job for this annotation

GitHub Actions / lint

Comment should end in a period (godot)
IdentityStateGeneratingPostProof
IdentityStatePostProofReady
IdentityStatePostProofFailed

// atx

Check failure on line 40 in activation/identity_states.go

View workflow job for this annotation

GitHub Actions / lint

Comment should end in a period (godot)
IdentityStateATXExpired
IdentityStateATXReady
IdentityStateATXBroadcasted
)

func (s IdentityState) String() string {
switch s {
case IdentityStateNotSet:
return "not set"
case IdentityStateWaitForATXSyncing:
return "wait for atx syncing"
case IdentityStatePoetChallengeReady:
return "poet challenge ready"
case IdentityStateWaitingForPoetRegistrationWindow:
return "waiting for poet registration window"
case IdentityStatePoetRegistered:
return "poet registered"
case IdentityStateWaitForPoetRoundEnd:
return "wait for poet round end"
case IdentityStatePoetProofReceived:
return "poet proof received"
case IdentityStatePoetProofFailed:
return "poet proof failed"
case IdentityStateGeneratingPostProof:
return "generating post proof"
case IdentityStatePostProofReady:
return "post proof ready"
case IdentityStatePostProofFailed:
return "post proof failed"
case IdentityStateATXReady:
return "atx ready"
case IdentityStateATXBroadcasted:
return "atx broadcasted"
default:
panic(fmt.Sprintf(ErrIdentityStateUnknown.Error()+" %d", s))

Check warning on line 75 in activation/identity_states.go

View check run for this annotation

Codecov / codecov/patch

activation/identity_states.go#L46-L75

Added lines #L46 - L75 were not covered by tests
}
}

type IdentityStateInfo struct {
Message string
Time time.Time
}

type IdentityInfo struct {
PublishEpoch types.EpochID
States map[IdentityState]IdentityStateInfo
}

type Identity struct {
EpochStates map[types.EpochID]*IdentityInfo
States map[IdentityState]IdentityStateInfo
}

type IdentityStateStorage struct {
mu sync.RWMutex
identities map[types.NodeID]*Identity
}

func NewIdentityStateStorage() *IdentityStateStorage {
return &IdentityStateStorage{
identities: make(map[types.NodeID]*Identity),
}
}

// TODO: validate state switch
//var validStateSwitch = map[IdentityState][]IdentityState{
// IdentityStateWaitForATXSyncing: {
// IdentityStateWaitForPoetRoundStart,
// },
// IdentityStatePostProving: {
// IdentityStateWaitForPoetRoundStart,
// },
// IdentityStateWaitForPoetRoundStart: {
// IdentityStateWaitForPoetRoundEnd,
// IdentityStateWaitForATXSyncing,
// },
// IdentityStateWaitForPoetRoundEnd: {
// IdentityStateFetchingProofs,
// IdentityStateWaitForPoetRoundStart,
// },
// IdentityStateFetchingProofs: {
// IdentityStatePostProving,
// IdentityStateWaitForPoetRoundStart,
// },
//}

func (s *IdentityStateStorage) Set(id types.NodeID, publishEpoch *types.EpochID, newState IdentityState, message string) {
s.mu.Lock()
defer s.mu.Unlock()

if _, exists := s.identities[id]; !exists {
s.identities[id] = &Identity{
EpochStates: map[types.EpochID]*IdentityInfo{},
States: map[IdentityState]IdentityStateInfo{},
}
}

if publishEpoch != nil {
if _, exists := s.identities[id].EpochStates[*publishEpoch]; !exists {
s.identities[id].EpochStates[*publishEpoch] = &IdentityInfo{
PublishEpoch: *publishEpoch,
States: make(map[IdentityState]IdentityStateInfo),
}
}
s.identities[id].EpochStates[*publishEpoch].States[newState] = IdentityStateInfo{
Time: time.Now(),
Message: message,
}
} else {
s.identities[id].States[newState] = IdentityStateInfo{
Time: time.Now(),
Message: message,
}
}
// TODO: validate state switch
//currentState, exists := s.states[id]
//switch {
//case !exists:
// if newState == IdentityStateWaitForATXSyncing {
// s.states[id] = newState
// return nil
// }
//case currentState == newState:
// return nil
//
//default:
// if validNextStates, ok := validStateSwitch[currentState]; ok &&
// slices.Contains(validNextStates, newState) {
// s.states[id] = newState
// return nil
// }
//}
//
//return fmt.Errorf(
// "%w: state %v can't be switched to %v",
// ErrInvalidIdentityStateSwitch,
// currentState,
// newState,
//)
}

func (s *IdentityStateStorage) Get(id types.NodeID) (*Identity, error) {
s.mu.RLock()
defer s.mu.RUnlock()

state, exists := s.identities[id]
if !exists {
return nil, ErrIdentityStateUnknown
}
return state, nil

Check warning on line 190 in activation/identity_states.go

View check run for this annotation

Codecov / codecov/patch

activation/identity_states.go#L182-L190

Added lines #L182 - L190 were not covered by tests
}

func (s *IdentityStateStorage) All() map[types.NodeID]*Identity {
s.mu.RLock()
defer s.mu.RUnlock()
return s.identities

Check warning on line 196 in activation/identity_states.go

View check run for this annotation

Codecov / codecov/patch

activation/identity_states.go#L193-L196

Added lines #L193 - L196 were not covered by tests
}
6 changes: 6 additions & 0 deletions activation/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,9 @@ type PostStates interface {
Set(id types.NodeID, state types.PostState)
Get() map[types.NodeID]types.PostState
}

type IdentityStates interface {
Set(id types.NodeID, publishEpoch *types.EpochID, newState IdentityState, message string)
Get(id types.NodeID) (*Identity, error)
All() map[types.NodeID]*Identity
}
Loading

0 comments on commit 7ec1727

Please sign in to comment.