diff --git a/chain/metrics/consensus.go b/chain/metrics/consensus.go new file mode 100644 index 000000000..afcf893b8 --- /dev/null +++ b/chain/metrics/consensus.go @@ -0,0 +1,83 @@ +package metrics + +import ( + "context" + "encoding/json" + "go.uber.org/fx" + + logging "github.com/ipfs/go-log" + pubsub "github.com/libp2p/go-libp2p-pubsub" + + "github.com/filecoin-project/go-lotus/node/impl/full" + "github.com/filecoin-project/go-lotus/node/modules/helpers" +) + +var log = logging.Logger("metrics") + +const baseTopic = "/fil/headnotifs/" + +type Update struct { + Type string +} + +func SendHeadNotifs(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, chain full.ChainAPI) error { + ctx := helpers.LifecycleCtx(mctx, lc) + + gen, err := chain.Chain.GetGenesis() + if err != nil { + return err + } + + topic := baseTopic + gen.Cid().String() + + go func() { + if err := sendHeadNotifs(ctx, ps, topic, chain); err != nil { + log.Error("consensus metrics error", err) + return + } + }() + go func() { + sub, err := ps.Subscribe(topic) + if err != nil { + return + } + defer sub.Cancel() + + for { + if _, err := sub.Next(ctx); err != nil { + return + } + } + + }() + + return err +} + +func sendHeadNotifs(ctx context.Context, ps *pubsub.PubSub, topic string, chain full.ChainAPI) error { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + notifs, err := chain.ChainNotify(ctx) + if err != nil { + return err + } + + for { + select { + case notif := <-notifs: + n := notif[len(notif)-1] + + b, err := json.Marshal(n.Val) + if err != nil { + return err + } + + if err := ps.Publish(topic, b); err != nil { + return err + } + case <-ctx.Done(): + return nil + } + } +} diff --git a/cmd/lotus-townhall/main.go b/cmd/lotus-townhall/main.go new file mode 100644 index 000000000..64b7f423c --- /dev/null +++ b/cmd/lotus-townhall/main.go @@ -0,0 +1,108 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "strings" + + "github.com/gorilla/websocket" + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p-core/peer" + pnet "github.com/libp2p/go-libp2p-pnet" + pubsub "github.com/libp2p/go-libp2p-pubsub" + + "github.com/filecoin-project/go-lotus/lib/addrutil" + "github.com/filecoin-project/go-lotus/node/modules/lp2p" +) + +const topic = "/fil/headnotifs/bafy2bzacedjqrkfbuafakygo6vlkrqozvsju2d5k6g24ry3mjjfxwrvet2636" + +var upgrader = websocket.Upgrader{ + WriteBufferSize: 1024, + CheckOrigin: func(r *http.Request) bool { + return true + }, +} + +func main() { + ctx := context.Background() + + protec, err := pnet.NewProtector(strings.NewReader(lp2p.LotusKey)) + if err != nil { + panic(err) + } + + host, err := libp2p.New( + ctx, + libp2p.Defaults, + libp2p.PrivateNetwork(protec), + ) + if err != nil { + panic(err) + } + ps, err := pubsub.NewGossipSub(ctx, host) + if err != nil { + panic(err) + } + + pi, err := addrutil.ParseAddresses(ctx, []string{ + "/ip4/147.75.80.29/tcp/1347/p2p/12D3KooWAShT7qd3oM7QPC8AsQffs6ThH69fZGui4xCW68E35rDP", + }) + if err != nil { + panic(err) + } + + if err := host.Connect(ctx, pi[0]); err != nil { + panic(err) + } + + http.HandleFunc("/sub", handler(ps)) + + fmt.Println("listening") + + if err := http.ListenAndServe("0.0.0.0:2975", nil); err != nil { + panic(err) + } +} + +type update struct { + From peer.ID + Update json.RawMessage +} + +func handler(ps *pubsub.PubSub) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + if r.Header.Get("Sec-WebSocket-Protocol") != "" { + w.Header().Set("Sec-WebSocket-Protocol", r.Header.Get("Sec-WebSocket-Protocol")) + } + + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + return + } + + sub, err := ps.Subscribe(topic) + if err != nil { + return + } + + for { + msg, err := sub.Next(r.Context()) + if err != nil { + return + } + + fmt.Println(msg) + + if err := conn.WriteJSON(update{ + From: peer.ID(msg.From), + Update: msg.Data, + }); err != nil { + return + } + } + } +} diff --git a/cmd/lotus-townhall/townhall/.gitignore b/cmd/lotus-townhall/townhall/.gitignore new file mode 100644 index 000000000..4d29575de --- /dev/null +++ b/cmd/lotus-townhall/townhall/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/cmd/lotus-townhall/townhall/package.json b/cmd/lotus-townhall/townhall/package.json new file mode 100644 index 000000000..5a8167622 --- /dev/null +++ b/cmd/lotus-townhall/townhall/package.json @@ -0,0 +1,31 @@ +{ + "name": "townhall", + "version": "0.1.0", + "private": true, + "dependencies": { + "react": "^16.10.2", + "react-dom": "^16.10.2", + "react-scripts": "3.2.0" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/cmd/lotus-townhall/townhall/public/index.html b/cmd/lotus-townhall/townhall/public/index.html new file mode 100644 index 000000000..38af10597 --- /dev/null +++ b/cmd/lotus-townhall/townhall/public/index.html @@ -0,0 +1,13 @@ + + + + + + + Lotus TownHall + + + +
+ + diff --git a/cmd/lotus-townhall/townhall/public/robots.txt b/cmd/lotus-townhall/townhall/public/robots.txt new file mode 100644 index 000000000..01b0f9a10 --- /dev/null +++ b/cmd/lotus-townhall/townhall/public/robots.txt @@ -0,0 +1,2 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * diff --git a/cmd/lotus-townhall/townhall/src/App.css b/cmd/lotus-townhall/townhall/src/App.css new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/cmd/lotus-townhall/townhall/src/App.css @@ -0,0 +1 @@ + diff --git a/cmd/lotus-townhall/townhall/src/App.js b/cmd/lotus-townhall/townhall/src/App.js new file mode 100644 index 000000000..10a835c14 --- /dev/null +++ b/cmd/lotus-townhall/townhall/src/App.js @@ -0,0 +1,37 @@ +import React from 'react'; +import './App.css'; + +class App extends React.Component { + constructor(props) { + super(props); + + //let ws = new WebSocket("ws://" + window.location.host + "/sub") + let ws = new WebSocket("ws://127.0.0.1:2975/sub") + + ws.onmessage = (ev) => { + console.log(ev) + let update = JSON.parse(ev.data) + + this.setState( prev => ({ + ...prev, [update.From]: update.Update, + })) + } + + this.state = {} + } + + render() { + let best = Object.keys(this.state).map(k => this.state[k]).reduce((p, n) => p > n.Height ? p : n.Height, -1) + console.log(best) + + return Object.keys(this.state).map(k => [k, this.state[k]]).map(([k, v]) => { + let l = {k} {v.Height} + if(best !== v.Height) { + l = {l} + } + + return
{l}
+ }) + } +} +export default App; diff --git a/cmd/lotus-townhall/townhall/src/App.test.js b/cmd/lotus-townhall/townhall/src/App.test.js new file mode 100644 index 000000000..a754b201b --- /dev/null +++ b/cmd/lotus-townhall/townhall/src/App.test.js @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + ReactDOM.unmountComponentAtNode(div); +}); diff --git a/cmd/lotus-townhall/townhall/src/index.css b/cmd/lotus-townhall/townhall/src/index.css new file mode 100644 index 000000000..fb0d9d10e --- /dev/null +++ b/cmd/lotus-townhall/townhall/src/index.css @@ -0,0 +1,6 @@ +body { + margin: 0; + font-family: monospace; + background: #1f1f1f; + color: #f0f0f0; +} diff --git a/cmd/lotus-townhall/townhall/src/index.js b/cmd/lotus-townhall/townhall/src/index.js new file mode 100644 index 000000000..395b74997 --- /dev/null +++ b/cmd/lotus-townhall/townhall/src/index.js @@ -0,0 +1,6 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import './index.css'; +import App from './App'; + +ReactDOM.render(, document.getElementById('root')); diff --git a/node/builder.go b/node/builder.go index 67c91345c..1e5b2eada 100644 --- a/node/builder.go +++ b/node/builder.go @@ -20,6 +20,7 @@ import ( "github.com/filecoin-project/go-lotus/api" "github.com/filecoin-project/go-lotus/chain" "github.com/filecoin-project/go-lotus/chain/deals" + "github.com/filecoin-project/go-lotus/chain/metrics" "github.com/filecoin-project/go-lotus/chain/stmgr" "github.com/filecoin-project/go-lotus/chain/store" "github.com/filecoin-project/go-lotus/chain/types" @@ -90,6 +91,7 @@ const ( // daemon ExtractApiKey + HeadMetricsKey SetApiEndpointKey @@ -225,6 +227,7 @@ func Online() Option { Override(RunHelloKey, modules.RunHello), Override(RunBlockSyncKey, modules.RunBlockSync), Override(HandleIncomingBlocksKey, modules.HandleIncomingBlocks), + Override(HeadMetricsKey, metrics.SendHeadNotifs), Override(new(*discovery.Local), discovery.NewLocal), Override(new(discovery.PeerResolver), modules.RetrievalResolver), diff --git a/node/modules/lp2p/pnet.go b/node/modules/lp2p/pnet.go index ffae463f8..3fe8e89df 100644 --- a/node/modules/lp2p/pnet.go +++ b/node/modules/lp2p/pnet.go @@ -8,12 +8,12 @@ import ( pnet "github.com/libp2p/go-libp2p-pnet" ) -var lotusKey = "/key/swarm/psk/1.0.0/\n/base16/\n20c72398e6299c7bbc1b501fdcc8abe4f89f798e9b93b2d2bc02e3c29b6a088e" +var LotusKey = "/key/swarm/psk/1.0.0/\n/base16/\n20c72398e6299c7bbc1b501fdcc8abe4f89f798e9b93b2d2bc02e3c29b6a088e" type PNetFingerprint []byte func PNet() (opts Libp2pOpts, fp PNetFingerprint, err error) { - protec, err := pnet.NewProtector(strings.NewReader(lotusKey)) + protec, err := pnet.NewProtector(strings.NewReader(LotusKey)) if err != nil { return opts, nil, fmt.Errorf("failed to configure private network: %s", err) }