Skip to content

Commit b83cb12

Browse files
authored
Merge pull request #11 from algorand/will/upgrade-vote-progress
Add consensus voting progress.
2 parents eacfc62 + 4b3bc82 commit b83cb12

File tree

3 files changed

+84
-30
lines changed

3 files changed

+84
-30
lines changed

tui/internal/bubbles/explorer/blocks.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import (
1212
"github.com/charmbracelet/lipgloss"
1313
)
1414

15-
// blockItem is used by the list bubble.
16-
type blockItem struct {
15+
// BlockItem is used by the list bubble.
16+
type BlockItem struct {
1717
Round uint64
1818
Block models.BlockResponse
1919
}
@@ -54,7 +54,7 @@ func proposer(cert *map[string]interface{}) string {
5454
return "<unknown>"
5555
}
5656

57-
func computeBlockRow(b blockItem) string {
57+
func computeBlockRow(b BlockItem) string {
5858
block := b.Block.Block
5959

6060
typeCount := make(map[types.TxType]uint)
@@ -117,7 +117,7 @@ func computeBlockRow(b blockItem) string {
117117
}
118118

119119
// Render implements the Row interface to display a row of data.
120-
func (i blockItem) Render(w io.Writer, model table.Model, index int) {
120+
func (i BlockItem) Render(w io.Writer, model table.Model, index int) {
121121
var cursor string
122122
if index == model.Cursor() {
123123
cursor = "> "

tui/internal/bubbles/explorer/explorer.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const (
2626

2727
const initialBlocks = 25
2828

29-
type blocks []blockItem
29+
type blocks []BlockItem
3030
type txnItems []transactionItem
3131

3232
// Model for the block explorer bubble.
@@ -67,16 +67,16 @@ func New(styles *style.Styles, requestor *messages.Requestor, width, widthMargin
6767

6868
// BlocksMsg contains new block information.
6969
type BlocksMsg struct {
70-
blocks []blockItem
71-
err error
70+
Blocks []BlockItem
71+
Err error
7272
}
7373

7474
// initBlocksCmd is the initializer command.
7575
func (m Model) initBlocksCmd() tea.Msg {
7676
status, err := m.requestor.Client.Status().Do(context.Background())
7777
if err != nil {
7878
return BlocksMsg{
79-
err: err,
79+
Err: err,
8080
}
8181
}
8282
return m.getBlocks(status.LastRound-initialBlocks, status.LastRound)()
@@ -88,16 +88,16 @@ func (m *Model) getBlocks(first, last uint64) tea.Cmd {
8888
for i := last; i >= first; i-- {
8989
block, err := m.requestor.Client.BlockRaw(i).Do(context.Background())
9090
if err != nil {
91-
result.err = err
91+
result.Err = err
9292
return result
9393
}
94-
item := blockItem{Round: i}
94+
item := BlockItem{Round: i}
9595
err = msgpack.Decode(block, &item.Block)
9696
if err != nil {
97-
result.err = err
97+
result.Err = err
9898
return result
9999
}
100-
result.blocks = append(result.blocks, item)
100+
result.Blocks = append(result.Blocks, item)
101101
}
102102
return result
103103
}
@@ -116,26 +116,26 @@ func (m Model) nextBlockCmd(round uint64) tea.Cmd {
116116
return func() tea.Msg {
117117
_, err := m.requestor.Client.StatusAfterBlock(round).Do(context.Background())
118118
if err != nil {
119-
return BlocksMsg{err: err}
119+
return BlocksMsg{Err: err}
120120
}
121121
blk, err := m.requestor.Client.BlockRaw(round).Do(context.Background())
122122
if err != nil {
123-
return BlocksMsg{err: err}
123+
return BlocksMsg{Err: err}
124124
}
125-
item := blockItem{Round: round}
126-
//err = msgpack.Decode(blk, &item.Block)
125+
item := BlockItem{Round: round}
126+
//Err = msgpack.Decode(blk, &item.Block)
127127
err = lenientDecode(blk, &item.Block)
128128
if err != nil {
129129
return err
130130
}
131131

132132
if err != nil {
133133
return BlocksMsg{
134-
err: err,
134+
Err: err,
135135
}
136136
}
137137
return BlocksMsg{
138-
blocks: []blockItem{item},
138+
Blocks: []BlockItem{item},
139139
}
140140
}
141141
}
@@ -163,7 +163,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
163163
// Select transactions.
164164
m.state = paysetState
165165
switch block := m.table.SelectedRow().(type) {
166-
case blockItem:
166+
case BlockItem:
167167
m.transactions = make([]transactionItem, 0)
168168
for _, txn := range block.Block.Block.Payset {
169169
t := txn
@@ -194,9 +194,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
194194
m.setSize(msg.Width, msg.Height)
195195

196196
case BlocksMsg:
197-
// append blocks
197+
// append Blocks
198198
backup := m.blocks
199-
m.blocks = msg.blocks
199+
m.blocks = msg.Blocks
200200
m.blocks = append(m.blocks, backup...)
201201
next := uint64(0)
202202
if len(m.blocks) > 0 {

tui/internal/bubbles/status/status.go

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,28 @@ import (
99

1010
"github.com/charmbracelet/bubbles/progress"
1111
tea "github.com/charmbracelet/bubbletea"
12+
"github.com/charmbracelet/lipgloss"
1213

1314
"github.com/algorand/go-algorand-sdk/client/v2/common/models"
15+
"github.com/algorand/go-algorand-sdk/types"
1416

1517
"github.com/algorand/node-ui/messages"
18+
"github.com/algorand/node-ui/tui/internal/bubbles/explorer"
1619
"github.com/algorand/node-ui/tui/internal/style"
1720
)
1821

22+
const roundTo = time.Second / 10
23+
24+
// consensus constants, in theory these could be modified by a consensus upgrade.
25+
const (
26+
upgradeVoteRounds = 10000
27+
upgradeThreshold = 9000
28+
)
29+
1930
// Model representing the status.
2031
type Model struct {
2132
Status models.NodeStatus
33+
Header types.BlockHeader
2234
Network messages.NetworkMsg
2335
Err error
2436

@@ -71,6 +83,18 @@ func (m Model) averageBlockTime() time.Duration {
7183
// Update is part of the tea.Model interface.
7284
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
7385
switch msg := msg.(type) {
86+
case explorer.BlocksMsg:
87+
// Still initializing.
88+
if m.Status.LastRound == 0 {
89+
return m, nil
90+
}
91+
92+
for _, blk := range msg.Blocks {
93+
if uint64(blk.Block.Block.Round) == m.Status.LastRound {
94+
m.Header = blk.Block.Block.BlockHeader
95+
}
96+
}
97+
return m, nil
7498
case messages.StatusMsg:
7599
if msg.Error != nil {
76100
m.Err = fmt.Errorf("error fetching status: %w", msg.Error)
@@ -80,14 +104,14 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
80104

81105
// Save the times for computing round time
82106
if m.latestBlock < m.Status.LastRound {
107+
since := time.Duration(m.Status.TimeSinceLastRound)
83108
m.latestBlock = m.Status.LastRound
84-
m.latestTime = time.Now().Add(-time.Duration(m.Status.TimeSinceLastRound))
109+
m.latestTime = time.Now().Add(-since)
85110

86111
// Grab the start time
87112
if m.startBlock == 0 {
88113
m.startBlock = m.Status.LastRound
89-
since := time.Duration(m.Status.TimeSinceLastRound)
90-
m.startTime = time.Now().Add(-since)
114+
m.startTime = m.latestTime
91115
}
92116
}
93117

@@ -107,14 +131,16 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
107131

108132
case messages.NetworkMsg:
109133
m.Network = msg
134+
return m, nil
110135

111136
case progress.FrameMsg:
112137
progressModel, cmd := m.progress.Update(msg)
113138
m.progress = progressModel.(progress.Model)
114139
return m, cmd
115-
}
116140

117-
return m, nil
141+
default:
142+
return m, nil
143+
}
118144
}
119145

120146
func formatVersion(v string) string {
@@ -131,6 +157,12 @@ func writeProgress(b *strings.Builder, prefix string, progress progress.Model, p
131157
b.WriteString("\n")
132158
}
133159

160+
func (m Model) calculateTimeToGo(start, end uint64, style lipgloss.Style) string {
161+
rounds := end - start
162+
timeRemaining := time.Duration(int64(rounds) * m.averageBlockTime().Nanoseconds()).Round(roundTo)
163+
return style.Render(fmt.Sprintf("%d to go, %s", rounds, timeRemaining))
164+
}
165+
134166
// View is part of the tea.Model interface.
135167
func (m Model) View() string {
136168
bold := m.style.StatusBoldText
@@ -166,12 +198,34 @@ func (m Model) View() string {
166198
height -= 7
167199
default:
168200
builder.WriteString(fmt.Sprintf("Current round: %s\n", key.Render(strconv.FormatUint(m.Status.LastRound, 10))))
169-
roundTo := time.Second / 10
170201
builder.WriteString(fmt.Sprintf("Block wait time: %s\n", time.Duration(m.Status.TimeSinceLastRound).Round(roundTo)))
171202
builder.WriteString(fmt.Sprintf("Sync time: %s\n", time.Duration(m.Status.CatchupTime).Round(roundTo)))
172203
height -= 3
173-
// TODO: Display consensus upgrade progress
174-
if m.Status.LastVersion == m.Status.NextVersion {
204+
if m.Header.UpgradeState != (types.UpgradeState{}) {
205+
//remainingToUpgrade := m.calculateTimeToGo(
206+
// m.Status.LastRound, uint64(m.Header.NextProtocolSwitchOn), m.style.AccountBlueText)
207+
remainingToVote := m.calculateTimeToGo(
208+
m.Status.LastRound, uint64(m.Header.NextProtocolVoteBefore), m.style.AccountBlueText)
209+
210+
// calculate yes/no votes
211+
votesToGo := uint64(m.Header.NextProtocolVoteBefore) - m.Status.LastRound
212+
votes := upgradeVoteRounds - votesToGo
213+
voteYes := m.Header.NextProtocolApprovals
214+
voteNo := votes - voteYes
215+
voteString := fmt.Sprintf("%d / %d", voteYes, voteNo)
216+
yesPct := float64(voteYes) / float64(votes)
217+
windowPct := float64(votes) / float64(upgradeVoteRounds)
218+
builder.WriteString(fmt.Sprintf("%s\n", bold.Render("Consensus Upgrade Pending: Votes")))
219+
builder.WriteString(fmt.Sprintf("Next Protocol: %s\n", formatVersion(m.Header.NextProtocol)))
220+
builder.WriteString(fmt.Sprintf("Yes/No votes: %s (%.0f%%, 90%% required)\n", voteString, yesPct*100))
221+
//builder.WriteString(fmt.Sprintf("Vote window: %s (%f%%)\n", voteString, *100))
222+
builder.WriteString(fmt.Sprintf("Vote window close: %d (%.0f%%, %s)\n",
223+
m.Header.UpgradeState.NextProtocolVoteBefore,
224+
windowPct*100,
225+
remainingToVote))
226+
227+
height -= 5
228+
} else if m.Status.LastVersion == m.Status.NextVersion {
175229
// no upgrade in progress
176230
builder.WriteString(fmt.Sprintf("Protocol: %s\n", formatVersion(m.Status.LastVersion)))
177231
builder.WriteString(fmt.Sprintf(" %s\n", bold.Render("No upgrade in progress.")))
@@ -184,7 +238,7 @@ func (m Model) View() string {
184238
fmt.Sprintf("%d to go, %s", togo, timeRemaining))
185239

186240
// upgrade in progress
187-
builder.WriteString(fmt.Sprintf("%s\n", bold.Render("Consensus Upgrade Pending")))
241+
builder.WriteString(fmt.Sprintf("%s\n", bold.Render("Consensus Upgrade Scheduled")))
188242
builder.WriteString(fmt.Sprintf("Current Protocol: %s\n", formatVersion(m.Status.LastVersion)))
189243
builder.WriteString(fmt.Sprintf("Next Protocol: %s\n", formatVersion(m.Status.NextVersion)))
190244
builder.WriteString(fmt.Sprintf("Upgrade round: %d (%s)\n", m.Status.NextVersionRound, remaining))

0 commit comments

Comments
 (0)