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

Feat/accounts page add incentive eligibility, fix: non-resident keys in txn modal #124

Merged
merged 7 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
67 changes: 57 additions & 10 deletions ui/modal/controller.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package modal

import (
"bytes"
"fmt"
"github.com/algorandfoundation/nodekit/internal/algod"
"github.com/algorandfoundation/nodekit/internal/algod/participation"
Expand All @@ -23,6 +24,13 @@
)
}

func boolToInt(input bool) int {
if input {
return 1
}
return 0

Check warning on line 31 in ui/modal/controller.go

View check run for this annotation

Codecov / codecov/patch

ui/modal/controller.go#L27-L31

Added lines #L27 - L31 were not covered by tests
}

// HandleMessage processes the given message, updates the ViewModel state, and returns any commands to execute.
func (m ViewModel) HandleMessage(msg tea.Msg) (*ViewModel, tea.Cmd) {
var (
Expand Down Expand Up @@ -75,24 +83,63 @@
// If the previous state is not active
if ok {
if !m.transactionModal.Active {
if acct.Participation != nil &&
acct.Participation.VoteFirstValid == m.transactionModal.Participation.Key.VoteFirstValid {
m.SetActive(true)
m.infoModal.Active = true
m.infoModal.Prefix = "Successfully registered online!\n"
m.HasPrefix = true
m.SetType(app.InfoModal)
if acct.Participation != nil && acct.Status == "Online" {
// comparing values to detect corrupted/non-resident keys
fvMatch := boolToInt(acct.Participation.VoteFirstValid == m.transactionModal.Participation.Key.VoteFirstValid)
PhearZero marked this conversation as resolved.
Show resolved Hide resolved
lvMatch := boolToInt(acct.Participation.VoteLastValid == m.transactionModal.Participation.Key.VoteLastValid)
kdMatch := boolToInt(acct.Participation.VoteKeyDilution == m.transactionModal.Participation.Key.VoteKeyDilution)
selMatch := boolToInt(bytes.Equal(acct.Participation.SelectionParticipationKey, m.transactionModal.Participation.Key.SelectionParticipationKey))
votMatch := boolToInt(bytes.Equal(acct.Participation.VoteParticipationKey, m.transactionModal.Participation.Key.VoteParticipationKey))
spkMatch := boolToInt(bytes.Equal(*acct.Participation.StateProofKey, *m.transactionModal.Participation.Key.StateProofKey))
matchCount := fvMatch + lvMatch + kdMatch + selMatch + votMatch + spkMatch
if matchCount == 6 {
m.SetActive(true)
m.infoModal.Active = true
m.infoModal.Prefix = "Successfully registered online!\n"
m.HasPrefix = true
m.SetType(app.InfoModal)
} else if matchCount >= 4 {
PhearZero marked this conversation as resolved.
Show resolved Hide resolved
// We use 4 as the "non resident key" threshold here
// because it would be valid to re-reg with a key that has the same fv / lv / kd
// but it would trigger the non resident condition
// TOOD: refactor this beast to have {previous state} -> compare with next state
m.SetActive(true)
m.infoModal.Active = true
m.infoModal.Prefix = "***WARNING***\nRegistered online but keys do not fully match\nCheck your registered keys carefully against the node keys\n\n"
if fvMatch == 0 {
m.infoModal.Prefix = m.infoModal.Prefix + "Mismatched: Vote First Valid\n"
}
if lvMatch == 0 {
m.infoModal.Prefix = m.infoModal.Prefix + "Mismatched: Vote Last Valid\n"
}
if kdMatch == 0 {
m.infoModal.Prefix = m.infoModal.Prefix + "Mismatched: Vote Key Dilution\n"
}
if votMatch == 0 {
m.infoModal.Prefix = m.infoModal.Prefix + "Mismatched: Vote Key\n"
}
if selMatch == 0 {
m.infoModal.Prefix = m.infoModal.Prefix + "Mismatched: Selection Key\n"
}
if spkMatch == 0 {
m.infoModal.Prefix = m.infoModal.Prefix + "Mismatched: State Proof Key\n"
}
m.HasPrefix = true
m.SetType(app.InfoModal)

Check warning on line 128 in ui/modal/controller.go

View check run for this annotation

Codecov / codecov/patch

ui/modal/controller.go#L86-L128

Added lines #L86 - L128 were not covered by tests
}
}
} else {
// TODO: This includes suspended keys, where Status == offline but .Participation is set
// Detect and display this

Check warning on line 133 in ui/modal/controller.go

View check run for this annotation

Codecov / codecov/patch

ui/modal/controller.go#L132-L133

Added lines #L132 - L133 were not covered by tests
if acct.Participation == nil {
m.SetActive(false)
m.infoModal.Active = false
m.transactionModal.Active = false
m.SetType(app.InfoModal)
} else {
m.SetSuspended()

Check warning on line 138 in ui/modal/controller.go

View check run for this annotation

Codecov / codecov/patch

ui/modal/controller.go#L136-L138

Added lines #L136 - L138 were not covered by tests
m.SetType(app.InfoModal)
}
}
}

}

case app.ModalEvent:
Expand Down
10 changes: 10 additions & 0 deletions ui/modal/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@
m.transactionModal.UpdateState()
}

// SetSuspended sets the active state to false both infoModal and transactionModal, and sets suspended state to true, also for both modals.
func (m *ViewModel) SetSuspended() {
m.infoModal.Active = false
m.infoModal.Suspended = true
m.infoModal.UpdateState()
m.transactionModal.Active = false
m.transactionModal.Suspended = true
m.transactionModal.UpdateState()

Check warning on line 79 in ui/modal/model.go

View check run for this annotation

Codecov / codecov/patch

ui/modal/model.go#L73-L79

Added lines #L73 - L79 were not covered by tests
}

func (m *ViewModel) SetShortLink(res participation.ShortLinkResponse) {
m.Link = &res
m.transactionModal.Link = &res
Expand Down
7 changes: 5 additions & 2 deletions ui/modals/info/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
Controls string
BorderColor string
Active bool
Suspended bool
Prefix string
Participation *api.ParticipationKey
State *algod.StateModel
Expand Down Expand Up @@ -74,9 +75,8 @@
if m.Participation == nil {
return
}
accountStatus := m.State.Accounts[m.Participation.Address].Status

if accountStatus == "Online" && m.Active {
if m.Active && !m.Suspended {
m.BorderColor = "1"
m.Controls = "( take " + style.Red.Render(style.Red.Render("(o)ffline")) + " )"
}
Expand All @@ -100,6 +100,9 @@
voteKeyDilution := style.Purple("Vote Key Dilution: ") + utils.IntToStr(m.Participation.Key.VoteKeyDilution)

prefix := ""
if m.Suspended {
prefix = "**KEY SUSPENDED**: Re-register online"
}

Check warning on line 105 in ui/modals/info/info.go

View check run for this annotation

Codecov / codecov/patch

ui/modals/info/info.go#L104-L105

Added lines #L104 - L105 were not covered by tests
if m.Prefix != "" {
prefix = "\n" + m.Prefix
}
Expand Down
1 change: 1 addition & 0 deletions ui/modals/transaction/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type ViewModel struct {
// Active Participation Key
Participation *api.ParticipationKey
Active bool
Suspended bool
Link *participation.ShortLinkResponse

// Pointer to the State
Expand Down
34 changes: 31 additions & 3 deletions ui/pages/accounts/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
"github.com/charmbracelet/lipgloss"
)

var minEligibleBalance = 30_000
var maxEligibleBalance = 70_000_000

type ViewModel struct {
Data *algod.StateModel

Expand Down Expand Up @@ -67,8 +70,8 @@
avgWidth := (width - lipgloss.Width(style.Border.Render("")) - 9) / 5
return []table.Column{
{Title: "Account", Width: avgWidth},
{Title: "Keys", Width: avgWidth},
{Title: "Status", Width: avgWidth},
{Title: "Rewards", Width: avgWidth},
{Title: "Expires", Width: avgWidth},
{Title: "Balance", Width: avgWidth},
}
Expand All @@ -78,11 +81,13 @@
rows := make([]table.Row, 0)

for addr := range m.Data.Accounts {
expired := false
var expires = "N/A"
if m.Data.Accounts[addr].Expires != nil {
// This condition will only exist for a split second
// until algod deletes the key
if m.Data.Accounts[addr].Expires.Before(time.Now()) {
expired = true

Check warning on line 90 in ui/pages/accounts/model.go

View check run for this annotation

Codecov / codecov/patch

ui/pages/accounts/model.go#L90

Added line #L90 was not covered by tests
expires = "EXPIRED"
} else {
expires = m.Data.Accounts[addr].Expires.Format(time.RFC822)
Expand All @@ -105,10 +110,33 @@
}
}

status := m.Data.Accounts[addr].Status
if status == "Online" && !expired {
status = "PARTICIPATING"

Check warning on line 115 in ui/pages/accounts/model.go

View check run for this annotation

Codecov / codecov/patch

ui/pages/accounts/model.go#L115

Added line #L115 was not covered by tests
} else {
status = "IDLE"
}

incentiveLevel := ""
balance := m.Data.Accounts[addr].Balance
if m.Data.Accounts[addr].IncentiveEligible && status == "PARTICIPATING" {
if balance >= minEligibleBalance && balance <= maxEligibleBalance {
incentiveLevel = "ELIGIBLE"
} else {
incentiveLevel = "PAUSED"
}

Check warning on line 127 in ui/pages/accounts/model.go

View check run for this annotation

Codecov / codecov/patch

ui/pages/accounts/model.go#L123-L127

Added lines #L123 - L127 were not covered by tests
} else {
if status == "PARTICIPATING" {
incentiveLevel = "INELIGIBLE"

Check warning on line 130 in ui/pages/accounts/model.go

View check run for this annotation

Codecov / codecov/patch

ui/pages/accounts/model.go#L130

Added line #L130 was not covered by tests
} else {
incentiveLevel = ""
}
}

rows = append(rows, table.Row{
m.Data.Accounts[addr].Address,
strconv.Itoa(m.Data.Accounts[addr].Keys),
m.Data.Accounts[addr].Status,
status,
incentiveLevel,
expires,
strconv.Itoa(m.Data.Accounts[addr].Balance),
})
Expand Down
4 changes: 2 additions & 2 deletions ui/pages/accounts/testdata/Test_Snapshot/Visible.golden
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
╭──Accounts────────────────────────────────────────────────────────────────────╮
│ Account Keys Status Expires Balance │
│ Account Status Rewards Expires Balance │
│─────────────────────────────────────────────────────────────────────────── │
│ ABC 2 Offline N/A 0 │
│ ABC IDLE N/A 0 │
│ │
│ │
│ │
Expand Down
Loading