Skip to content

Commit

Permalink
Add tx tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
Gustavo Chain committed Feb 27, 2020
1 parent 98f1ccb commit 1ec586f
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 29 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ go get -u github.com/gchaincl/mempool
```

# TODO
- [ ] Transaction Tracking (by Tx ID)
- [x] Transaction Tracking (by Tx ID) (using 'f' key)
- [x] Block details on click
- [ ] Graphs
- [ ] Tx weight per second progress bar
Expand Down
30 changes: 24 additions & 6 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,25 @@ type ProjectedBlock struct {
HasMyTx bool `json:"hasMytx"`
}

type TrackTx struct {
Tracking bool `json:"tracking"`
BlockHeight int `json:"blockHeight"`
Message string `json:"message"`
TX struct {
Status struct {
Confirmed bool
}
} `json:"tx"`
}

type Response struct {
MempoolInfo *MempoolInfo `json:"mempoolInfo"`

Block *Block `json:"block"`
Blocks []Block `json:"blocks"`

ProjectedBlocks []ProjectedBlock `json:"projectedBlocks"`
TrackTx TrackTx `json:"track-tx"`

TxPerSecond float64 `json:"txPerSecond"`
VBytesPerSecond int `json:"vBytesPerSecond"`
Expand All @@ -70,12 +82,6 @@ func New() (*Client, error) {
if err != nil {
return nil, err
}

if err := conn.WriteMessage(websocket.TextMessage, []byte(
`{"action":"want","data":["stats","blocks","projected-blocks"]}`,
)); err != nil {
return nil, err
}
return &Client{conn: conn}, nil
}

Expand All @@ -87,6 +93,18 @@ func (c *Client) Read() (*Response, error) {
return &resp, nil
}

func (c *Client) Want() error {
return c.conn.WriteMessage(websocket.TextMessage, []byte(
`{"action":"want","data":["stats","blocks","projected-blocks"]}`,
))
}

func (c *Client) Track(txId string) error {
return c.conn.WriteMessage(websocket.TextMessage, []byte(
fmt.Sprintf(`{"action":"track-tx","txId":"%s"}`, txId),
))
}

type Fees []struct {
FPV float64 `json:"fpv"`
}
Expand Down
17 changes: 0 additions & 17 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import (
"log"

"github.com/gchaincl/mempool/client"
"github.com/gchaincl/mempool/ui"
)

Expand All @@ -14,22 +13,6 @@ func main() {
}
defer gui.Close()

go func() {
c, err := client.New()
if err != nil {
log.Fatal(err)
}

for {
resp, err := c.Read()
if err != nil {
log.Fatal(err)
}

gui.Render(resp)
}
}()

if err := gui.Loop(); err != nil {
log.Fatal(err)
}
Expand Down
88 changes: 88 additions & 0 deletions ui/tx_search.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package ui

import (
"fmt"

"github.com/jroimartin/gocui"
)

type TXSearch struct {
gui *gocui.Gui

opened bool
txid string
cb func(string) error
}

func NewTXSearch(gui *gocui.Gui) *TXSearch {
ts := &TXSearch{gui: gui}
return ts
}

func (s *TXSearch) Callback(fn func(txId string) error) {
s.cb = fn
}

func (s *TXSearch) SetKeybinding() {
s.gui.SetKeybinding("", 'f', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
s.gui.DeleteKeybinding("", 'f', gocui.ModNone)
s.Open()
return nil
})
}

func (s *TXSearch) Layout(g *gocui.Gui) error {
name := "tx_search"
if !s.opened {
g.Cursor = false
g.DeleteView(name)
return nil
}

g.Cursor = true
x, y := g.Size()
v, err := g.SetView(name, x/2-35, y/2-1, x/2+35, y/2+1)
if err != nil {
if err != gocui.ErrUnknownView {
return err
}
v.Title = "Track transaction (txid)"
v.Editable = true
g.SetCurrentView(name)
v.Editor = gocui.EditorFunc(s.editFn)
v.Autoscroll = false
fmt.Fprintf(v, "%s", s.txid)
v.SetCursor(len(s.txid), 0)

g.SetKeybinding(v.Name(), gocui.KeyEsc, gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
s.Close()
return nil
})
}

return nil
}

func (s *TXSearch) editFn(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
switch key {
case gocui.KeyEnter:
if id := s.txid; id != "" {
s.cb(id)
}
s.Close()
case gocui.KeyArrowDown, gocui.KeyArrowUp:
return
}

gocui.DefaultEditor.Edit(v, key, ch, mod)
s.txid, _ = v.Line(0)
}

func (s *TXSearch) Open() {
s.opened = true
}

func (s *TXSearch) Close() {
s.SetKeybinding()
s.opened = false
}
61 changes: 56 additions & 5 deletions ui/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ui

import (
"fmt"
"log"
"strconv"
"strings"

Expand All @@ -20,12 +21,15 @@ type state struct {
projected []client.ProjectedBlock
vBytesPerSecond int
info *client.MempoolInfo
tracking *client.TrackTx
}

type UI struct {
gui *gocui.Gui
fd *FeeDistribution
state state
client *client.Client
gui *gocui.Gui
fd *FeeDistribution
ts *TXSearch
state state
}

func New() (*UI, error) {
Expand All @@ -36,14 +40,40 @@ func New() (*UI, error) {

ui := &UI{gui: gui}
ui.fd = NewFeeDistribution(gui)
gui.SetManager(ui, ui.fd)
ui.ts = NewTXSearch(gui)
gui.SetManager(ui, ui.fd, ui.ts)

gui.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit)
gui.SetKeybinding("", 'q', gocui.ModNone, quit)
ui.ts.SetKeybinding()

gui.Mouse = true
gui.Highlight = true
gui.InputEsc = true
gui.SelFgColor = gocui.ColorWhite

go func() {
c, err := client.New()
if err != nil {
log.Fatal(err)
}
if err := c.Want(); err != nil {
log.Fatal(err)
}
ui.client = c
ui.ts.Callback(func(txId string) error {
return c.Track(txId)
})

for {
resp, err := c.Read()
if err != nil {
log.Fatal(err)
}
ui.Render(resp)
}

}()

return ui, nil
}

Expand Down Expand Up @@ -87,6 +117,9 @@ func (ui *UI) Render(resp *client.Response) {
ui.state.info = info
}

// Update tracking info
ui.state.tracking = &resp.TrackTx

// delete all the views
for _, v := range ui.gui.Views() {
ui.gui.DeleteView(v.Name())
Expand All @@ -108,6 +141,8 @@ func (ui *UI) Layout(g *gocui.Gui) error {
// and the blockchain in the bottom
vertical := BLOCK_WIDTH*6 > x

track := ui.state.tracking

// draw projected blocks (mempool)
for i, _ := range ui.state.projected {
name := fmt.Sprintf("projected-block-%d", i)
Expand All @@ -131,6 +166,14 @@ func (ui *UI) Layout(g *gocui.Gui) error {
}
v.BgColor = gocui.ColorBlack
g.SetKeybinding(v.Name(), gocui.MouseLeft, gocui.ModNone, ui.onBlockClick)

if track.Tracking && !track.TX.Status.Confirmed {
if track.BlockHeight == i {
v.SelBgColor = gocui.ColorRed
v.SelFgColor = gocui.ColorRed
g.SetCurrentView(v.Name())
}
}
}

v.Clear()
Expand Down Expand Up @@ -166,9 +209,17 @@ func (ui *UI) Layout(g *gocui.Gui) error {
}
v.BgColor = gocui.ColorBlack
g.SetKeybinding(v.Name(), gocui.MouseLeft, gocui.ModNone, ui.onBlockClick)

}

v.Title = fmt.Sprintf("#%d", block.Height)
if track.Tracking && track.TX.Status.Confirmed {
if track.BlockHeight == block.Height {
v.SelBgColor = gocui.ColorRed
v.SelFgColor = gocui.ColorRed
g.SetCurrentView(v.Name())
}
}
v.Clear()
if _, err := v.Write(ui.printBlock(i, x1-x0, y1-y0)); err != nil {
return err
Expand Down

0 comments on commit 1ec586f

Please sign in to comment.