Merge pull request #149 from filecoin-project/feat/pond-gas-updates
pond: Gas-related updates
This commit is contained in:
commit
78b548ab2f
@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
logging.SetLogLevel("*", "DEBUG")
|
||||
logging.SetLogLevel("*", "INFO")
|
||||
local := []*cli.Command{
|
||||
DaemonCmd,
|
||||
}
|
||||
|
1
go.mod
1
go.mod
@ -59,6 +59,7 @@ require (
|
||||
github.com/multiformats/go-multiaddr-dns v0.0.3
|
||||
github.com/multiformats/go-multiaddr-net v0.0.1
|
||||
github.com/multiformats/go-multihash v0.0.6
|
||||
github.com/opentracing/opentracing-go v1.1.0
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a
|
||||
github.com/smartystreets/assertions v1.0.1 // indirect
|
||||
|
@ -65,9 +65,11 @@ func (api *api) Spawn() (nodeInfo, error) {
|
||||
return nodeInfo{}, err
|
||||
}
|
||||
|
||||
mux := newWsMux()
|
||||
|
||||
cmd := exec.Command("./lotus", "daemon", genParam, "--api", fmt.Sprintf("%d", 2500+id))
|
||||
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile)
|
||||
cmd.Stdout = io.MultiWriter(os.Stdout, logfile)
|
||||
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile, mux.errpw)
|
||||
cmd.Stdout = io.MultiWriter(os.Stdout, logfile, mux.outpw)
|
||||
cmd.Env = []string{"LOTUS_PATH=" + dir}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nodeInfo{}, err
|
||||
@ -84,7 +86,9 @@ func (api *api) Spawn() (nodeInfo, error) {
|
||||
cmd: cmd,
|
||||
meta: info,
|
||||
|
||||
mux: mux,
|
||||
stop: func() {
|
||||
defer close(mux.stop)
|
||||
defer errlogfile.Close()
|
||||
defer logfile.Close()
|
||||
},
|
||||
@ -156,9 +160,11 @@ func (api *api) SpawnStorage(fullNodeRepo string) (nodeInfo, error) {
|
||||
|
||||
time.Sleep(time.Millisecond * 300)
|
||||
|
||||
mux := newWsMux()
|
||||
|
||||
cmd = exec.Command("./lotus-storage-miner", "run", "--api", fmt.Sprintf("%d", 2500+id))
|
||||
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile)
|
||||
cmd.Stdout = io.MultiWriter(os.Stdout, logfile)
|
||||
cmd.Stderr = io.MultiWriter(os.Stderr, errlogfile, mux.errpw)
|
||||
cmd.Stdout = io.MultiWriter(os.Stdout, logfile, mux.outpw)
|
||||
cmd.Env = []string{"LOTUS_STORAGE_PATH=" + dir, "LOTUS_PATH=" + fullNodeRepo}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nodeInfo{}, err
|
||||
@ -178,7 +184,9 @@ func (api *api) SpawnStorage(fullNodeRepo string) (nodeInfo, error) {
|
||||
cmd: cmd,
|
||||
meta: info,
|
||||
|
||||
mux: mux,
|
||||
stop: func() {
|
||||
defer close(mux.stop)
|
||||
defer errlogfile.Close()
|
||||
defer logfile.Close()
|
||||
},
|
||||
|
15
lotuspond/front/package-lock.json
generated
15
lotuspond/front/package-lock.json
generated
@ -13075,6 +13075,21 @@
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||
},
|
||||
"xterm": {
|
||||
"version": "3.14.5",
|
||||
"resolved": "https://registry.npmjs.org/xterm/-/xterm-3.14.5.tgz",
|
||||
"integrity": "sha512-DVmQ8jlEtL+WbBKUZuMxHMBgK/yeIZwkXB81bH+MGaKKnJGYwA+770hzhXPfwEIokK9On9YIFPRleVp/5G7z9g=="
|
||||
},
|
||||
"xterm-addon-attach": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm-addon-attach/-/xterm-addon-attach-0.1.0.tgz",
|
||||
"integrity": "sha512-vImYAP+AVoW/gnr4CIESrOr2MplzNxnrPX4YEkdk0EEkBOg3Pwnndu1xy7HnY0XZsfGRz7rfn71sAXfJDGLvUQ=="
|
||||
},
|
||||
"xterm-addon-fit": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.1.0.tgz",
|
||||
"integrity": "sha512-DzYThnR5rXYX7JrOZ8rHGMU36BiTwYNFUOhhNwrDSFvoUR2MgwQrfA/JrqLE62KRj0D8bkRR7+xe7qGBp1O4Rw=="
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||
|
@ -13,7 +13,10 @@
|
||||
"react-dom": "^16.8.6",
|
||||
"react-scripts": "3.0.1",
|
||||
"rpc-websockets": "^4.5.1",
|
||||
"styled-components": "^3.3.3"
|
||||
"styled-components": "^3.3.3",
|
||||
"xterm": "^3.14.5",
|
||||
"xterm-addon-attach": "^0.1.0",
|
||||
"xterm-addon-fit": "^0.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
|
@ -4,9 +4,9 @@ import * as multihash from "multihashes";
|
||||
import State from "./State";
|
||||
import methods from "./chain/methods";
|
||||
|
||||
function truncAddr(addr) {
|
||||
if (addr.length > 21) {
|
||||
return <abbr title={addr}>{addr.substr(0, 18) + '..'}</abbr>
|
||||
function truncAddr(addr, len) {
|
||||
if (addr.length > len) {
|
||||
return <abbr title={addr}>{addr.substr(0, len - 3) + '..'}</abbr>
|
||||
}
|
||||
return addr
|
||||
}
|
||||
@ -72,7 +72,7 @@ class Address extends React.Component {
|
||||
if(this.props.add1k) {
|
||||
add1k = <span> <a href="#" onClick={() => this.props.add1k(this.props.addr)}>[+1k]</a></span>
|
||||
}
|
||||
let addr = truncAddr(this.props.addr)
|
||||
let addr = truncAddr(this.props.addr, this.props.short ? 12 : 17)
|
||||
|
||||
let actInfo = <span>(?)</span>
|
||||
if(this.state.balance >= 0) {
|
||||
@ -80,17 +80,21 @@ class Address extends React.Component {
|
||||
addr = <a href="#" onClick={this.openState}>{addr}</a>
|
||||
}
|
||||
|
||||
let balance = <span>: {this.state.balance}</span>
|
||||
let balance = <span>: {this.state.balance} </span>
|
||||
if(this.props.nobalance) {
|
||||
balance = <span></span>
|
||||
balance = <span/>
|
||||
}
|
||||
if(this.props.short) {
|
||||
actInfo = <span/>
|
||||
balance = <span/>
|
||||
}
|
||||
|
||||
let transfer = <span></span>
|
||||
let transfer = <span/>
|
||||
if(this.props.transfer) {
|
||||
transfer = <span> {this.props.transfer}FIL</span>
|
||||
}
|
||||
|
||||
return <span>{addr}{balance} {actInfo}{add1k}{transfer}</span>
|
||||
return <span>{addr}{balance}{actInfo}{add1k}{transfer}</span>
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,7 @@
|
||||
}
|
||||
|
||||
.ChainExplorer-at {
|
||||
min-width: 40em;
|
||||
background: #77ff77;
|
||||
}
|
||||
|
||||
@ -74,3 +75,12 @@
|
||||
.ChainExplorer-before {
|
||||
background: #cccc00
|
||||
}
|
||||
|
||||
.Logs {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.Logs-window :nth-child(2) {
|
||||
height: 100%;
|
||||
}
|
||||
|
@ -14,8 +14,16 @@ class Block extends React.Component {
|
||||
|
||||
async loadHeader() {
|
||||
const header = await this.props.conn.call('Filecoin.ChainGetBlock', [this.props.cid])
|
||||
const messages = await this.props.conn.call('Filecoin.ChainGetBlockMessages', [this.props.cid])
|
||||
console.log(messages)
|
||||
let messages = await this.props.conn.call('Filecoin.ChainGetBlockMessages', [this.props.cid])
|
||||
let receipts = await this.props.conn.call('Filecoin.ChainGetBlockReceipts', [this.props.cid])
|
||||
|
||||
messages = [
|
||||
...(messages.BlsMessages.map(m => ({...m, type: 'BLS'}))),
|
||||
...(messages.SecpkMessages.map(m => ({...(m.Message), type: 'Secpk'})))
|
||||
]
|
||||
|
||||
messages = messages.map((msg, k) => ({...msg, receipt: receipts[k]}))
|
||||
|
||||
this.setState({header: header, messages: messages})
|
||||
}
|
||||
|
||||
@ -24,15 +32,12 @@ class Block extends React.Component {
|
||||
if (this.state.header) {
|
||||
let head = this.state.header
|
||||
|
||||
|
||||
|
||||
let messages = [
|
||||
...(this.state.messages.BlsMessages.map(m => ({...m, type: 'BLS'}))),
|
||||
...(this.state.messages.SecpkMessages.map(m => ({...(m.Message), type: 'Secpk'})))
|
||||
].map(m => (
|
||||
const messages = this.state.messages.map(m => (
|
||||
<div>
|
||||
<Address client={this.props.conn} addr={m.From} mountWindow={this.props.mountWindow}/><b> => </b>
|
||||
<Address client={this.props.conn} addr={m.To} mountWindow={this.props.mountWindow} transfer={m.Value} method={m.Method}/>
|
||||
<span> {m.receipt.GasUsed}Gas</span>
|
||||
{m.receipt.ExitCode !== 0 ? <span> <b>EXIT:{m.receipt.ExitCode}</b></span> : <span/>}
|
||||
</div>
|
||||
))
|
||||
|
||||
|
@ -1,10 +1,19 @@
|
||||
import React from 'react';
|
||||
import Block from "./Block";
|
||||
import Address from "./Address";
|
||||
|
||||
|
||||
export class BlockLinks extends React.Component {
|
||||
render() {
|
||||
return this.props.cids.map(c => <BlockLink key={c} conn={this.props.conn} cid={c} mountWindow={this.props.mountWindow}/>)
|
||||
return this.props.cids.map((c, k) => {
|
||||
let block
|
||||
|
||||
if(this.props.blocks) {
|
||||
block = this.props.blocks[k]
|
||||
}
|
||||
|
||||
return <BlockLink key={c} block={block} conn={this.props.conn} cid={c} mountWindow={this.props.mountWindow}/>
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +29,12 @@ class BlockLink extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
return <a href="#" onClick={this.openBlockViewer}><abbr title={this.props.cid['/']}>{this.props.cid['/'].substr(-8)}</abbr></a>
|
||||
let info = <span></span>
|
||||
if(this.props.block) {
|
||||
info = <span> (by <Address client={this.props.conn} addr={this.props.block.Miner} mountWindow={this.props.mountWindow} short={true}/>)</span>
|
||||
}
|
||||
|
||||
return <span><a href="#" onClick={this.openBlockViewer}><abbr title={this.props.cid['/']}>{this.props.cid['/'].substr(-8)}</abbr></a>{info}</span>
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,12 +114,15 @@ class ChainExplorer extends React.Component {
|
||||
const ts = this.state.cache[row]
|
||||
|
||||
let msgc = -1
|
||||
if(ts.Cids[0] && this.state.messages[ts.Cids[0]['/']]) {
|
||||
if(ts.Cids[0] && this.state.messages[ts.Cids[0]['/']]) { // TODO: get from all blks
|
||||
msgc = this.state.messages[ts.Cids[0]['/']].SecpkMessages.length + this.state.messages[ts.Cids[0]['/']].BlsMessages.length
|
||||
}
|
||||
if(msgc > 0) {
|
||||
msgc = <b>{msgc}</b>
|
||||
}
|
||||
|
||||
info = <span>
|
||||
<BlockLinks cids={ts.Cids} conn={this.props.client} mountWindow={this.props.mountWindow} /> Msgs: <b>{msgc}</b>
|
||||
<BlockLinks cids={ts.Cids} blocks={ts.Blocks} conn={this.props.client} mountWindow={this.props.mountWindow} /> Msgs: {msgc}
|
||||
</span>
|
||||
}
|
||||
|
||||
|
@ -63,10 +63,10 @@ class FullNode extends React.Component {
|
||||
// TODO: Use actual miner address
|
||||
// see cli/miner.go
|
||||
this.setState({mining: true})
|
||||
let addr = "t0523423423" // in case we have no wallets
|
||||
if (this.state.defaultAddr) {
|
||||
let addr = "t0101" // in case we have no wallets
|
||||
/*if (this.state.defaultAddr) {
|
||||
addr = this.state.defaultAddr
|
||||
}
|
||||
}*/
|
||||
|
||||
this.setState({mining: true})
|
||||
await this.props.client.call("Filecoin.MinerStart", [addr])
|
||||
|
31
lotuspond/front/src/Logs.js
Normal file
31
lotuspond/front/src/Logs.js
Normal file
@ -0,0 +1,31 @@
|
||||
import React from 'react'
|
||||
import {Cristal} from "react-cristal";
|
||||
import { Terminal } from 'xterm';
|
||||
import { AttachAddon } from "xterm-addon-attach";
|
||||
import 'xterm/dist/xterm.css';
|
||||
import * as fit from 'xterm/lib/addons/fit/fit';
|
||||
|
||||
class Logs extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.termRef = React.createRef()
|
||||
this.winRef = React.createRef()
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
Terminal.applyAddon(fit);
|
||||
|
||||
this.terminal = new Terminal({convertEol: true, fontSize: 11});
|
||||
this.terminal.loadAddon(new AttachAddon(new WebSocket(`ws://127.0.0.1:2222/logs/${this.props.node}`), {bidirectional: false, inputUtf8: true}))
|
||||
this.terminal.open(this.termRef.current)
|
||||
setInterval(() => this.terminal.fit(), 200)
|
||||
}
|
||||
|
||||
render() {
|
||||
return <Cristal className="Logs-window" onClose={this.props.onClose} initialSize={{width: 1000, height: 480}} title={`Node ${this.props.node} Logs`}>
|
||||
<div ref={this.termRef} className="Logs"/>
|
||||
</Cristal>
|
||||
}
|
||||
}
|
||||
|
||||
export default Logs
|
@ -6,6 +6,7 @@ import {Cristal} from "react-cristal";
|
||||
import StorageNode from "./StorageNode";
|
||||
import {Client} from "rpc-websockets";
|
||||
import pushMessage from "./chain/send";
|
||||
import Logs from "./Logs";
|
||||
|
||||
class NodeList extends React.Component {
|
||||
constructor(props) {
|
||||
@ -130,13 +131,15 @@ class NodeList extends React.Component {
|
||||
type = "STOR"
|
||||
}
|
||||
|
||||
let logs = "[logs]"
|
||||
let info = "[CONNECTING..]"
|
||||
if (nd.conn) {
|
||||
info = <span>{nd.peerid}</span>
|
||||
logs = <a href='#' onClick={() => this.props.mountWindow(cl => <Logs node={nd.ID} onClose={cl}/>)}>[logs]</a>
|
||||
}
|
||||
|
||||
return <div key={n}>
|
||||
{n} {type} {info}
|
||||
{n} {type} {logs} {info}
|
||||
</div>
|
||||
})}
|
||||
</div>
|
||||
|
@ -4,7 +4,7 @@ import { Tagged } from 'borc'
|
||||
|
||||
async function pushMessage(client, from, inmsg) {
|
||||
if(!inmsg.GasLimit) {
|
||||
inmsg.GasLimit = "0"
|
||||
inmsg.GasLimit = "1000"
|
||||
}
|
||||
if(!inmsg.GasPrice) {
|
||||
inmsg.GasPrice = "0"
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/lib/jsonrpc"
|
||||
@ -18,6 +19,7 @@ type runningNode struct {
|
||||
cmd *exec.Cmd
|
||||
meta nodeInfo
|
||||
|
||||
mux *outmux
|
||||
stop func()
|
||||
}
|
||||
|
||||
@ -107,15 +109,33 @@ func nodeById(nodes []nodeInfo, i int) nodeInfo {
|
||||
panic("no node with this id")
|
||||
}
|
||||
|
||||
func logHandler(api *api) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, req *http.Request) {
|
||||
id, err := strconv.ParseInt(path.Base(req.URL.Path), 10, 32)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return
|
||||
}
|
||||
|
||||
api.runningLk.Lock()
|
||||
n := api.running[int32(id)]
|
||||
api.runningLk.Unlock()
|
||||
|
||||
n.mux.ServeHTTP(w, req)
|
||||
}
|
||||
}
|
||||
|
||||
var runCmd = &cli.Command{
|
||||
Name: "run",
|
||||
Usage: "run lotuspond daemon",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
rpcServer := jsonrpc.NewServer()
|
||||
rpcServer.Register("Pond", &api{running: map[int32]runningNode{}})
|
||||
a := &api{running: map[int32]runningNode{}}
|
||||
rpcServer.Register("Pond", a)
|
||||
|
||||
http.Handle("/", http.FileServer(http.Dir("lotuspond/front/build")))
|
||||
http.Handle("/rpc/v0", rpcServer)
|
||||
http.HandleFunc("/logs/", logHandler(a))
|
||||
|
||||
fmt.Printf("Listening on http://%s\n", listenAddr)
|
||||
return http.ListenAndServe(listenAddr, nil)
|
||||
|
124
lotuspond/outmux.go
Normal file
124
lotuspond/outmux.go
Normal file
@ -0,0 +1,124 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/opentracing/opentracing-go/log"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type outmux struct {
|
||||
lk sync.Mutex
|
||||
|
||||
errpw *io.PipeWriter
|
||||
outpw *io.PipeWriter
|
||||
|
||||
errpr *io.PipeReader
|
||||
outpr *io.PipeReader
|
||||
|
||||
n uint64
|
||||
outs map[uint64]*websocket.Conn
|
||||
|
||||
new chan *websocket.Conn
|
||||
stop chan struct{}
|
||||
}
|
||||
|
||||
func newWsMux() *outmux {
|
||||
out := &outmux{
|
||||
n: 0,
|
||||
outs: map[uint64]*websocket.Conn{},
|
||||
new: make(chan *websocket.Conn),
|
||||
stop: make(chan struct{}),
|
||||
}
|
||||
|
||||
out.outpr, out.outpw = io.Pipe()
|
||||
out.errpr, out.errpw = io.Pipe()
|
||||
|
||||
go out.run()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func (m *outmux) msgsToChan(r *io.PipeReader, ch chan []byte) {
|
||||
defer close(ch)
|
||||
for {
|
||||
buf := make([]byte, 1)
|
||||
n, err := r.Read(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case ch <- buf[:n]:
|
||||
case <-m.stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *outmux) run() {
|
||||
stdout := make(chan []byte)
|
||||
stderr := make(chan []byte)
|
||||
go m.msgsToChan(m.outpr, stdout)
|
||||
go m.msgsToChan(m.errpr, stderr)
|
||||
|
||||
for {
|
||||
select {
|
||||
case msg := <-stdout:
|
||||
for k, out := range m.outs {
|
||||
if err := out.WriteMessage(websocket.BinaryMessage, msg); err != nil {
|
||||
out.Close()
|
||||
fmt.Printf("outmux write failed: %s\n", err)
|
||||
delete(m.outs, k)
|
||||
}
|
||||
}
|
||||
case msg := <-stderr:
|
||||
for k, out := range m.outs {
|
||||
if err := out.WriteMessage(websocket.BinaryMessage, msg); err != nil {
|
||||
out.Close()
|
||||
fmt.Printf("outmux write failed: %s\n", err)
|
||||
delete(m.outs, k)
|
||||
}
|
||||
}
|
||||
case c := <-m.new:
|
||||
m.n++
|
||||
m.outs[m.n] = c
|
||||
case <-m.stop:
|
||||
for _, out := range m.outs {
|
||||
out.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
}
|
||||
|
||||
func (m *outmux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.Contains(r.Header.Get("Connection"), "Upgrade") {
|
||||
fmt.Println("noupgrade")
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
|
||||
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"))
|
||||
}
|
||||
|
||||
c, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
|
||||
m.new <- c
|
||||
return
|
||||
}
|
@ -80,6 +80,8 @@ func (m *Miner) Mine(ctx context.Context) {
|
||||
b, err := m.mineOne(ctx, base)
|
||||
if err != nil {
|
||||
log.Errorf("mining block failed: %s", err)
|
||||
log.Warn("waiting 400ms before attempting to mine a block")
|
||||
time.Sleep(400 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user