Skip to content

Commit

Permalink
Merge pull request #33 from Impa10r/v1.3.4
Browse files Browse the repository at this point in the history
v1.3.4
  • Loading branch information
Impa10r authored May 3, 2024
2 parents d8a4c4f + 16f6e0f commit a5cc3fc
Show file tree
Hide file tree
Showing 20 changed files with 693 additions and 212 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"type": "go",
"request": "launch",
"mode": "auto",
"buildFlags": "-tags cln",
"buildFlags": "-tags lnd",
"program": "${workspaceFolder}/cmd/psweb/",
"showLog": false,
"envFile": "${workspaceFolder}/.env",
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Versions

## 1.3.4

- Display channel flows since their last swaps
- Allow filtering swaps history
- Speed up loading of pages
- Display current fee rates for channels
- Add help tooltips
- CLN: implement incremental forwards history polling
- LND 0.18+: exact fee when sending change-less peg-in tx (there was a bug in LND below 0.18)

## 1.3.3

- Add channel routing statistics on the peer screen
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Once opened the UI, set the Links on the Config page for testnet or mainnet. If

To enable downloading of a backup file of the Elements wallet it is necessary to have access to .elements folder where this backup is saved by elementsd. If Elements is run in a Docker container, both the internal folder (usually /home/elements/.elements) and the mapped external folder (for Umbrel it is /home/umbrel/umbrel/app-data/elements/data) must be provided in the Configuration panel.

***Warning*** If you tried a Docker version first and then switched to the one built from source, the configuration files will be incorrect. The easiest way to fix this is to delete ```peerswap.conf``` and ```pswebconfig.json```.
***Warning*** If you tried PS Web's Docker version first and then switched to the one built from source, the configuration files will be incorrect. The easiest way to fix this is to delete ```peerswap.conf``` and ```pswebconfig.json```.

## Update

Expand Down
5 changes: 4 additions & 1 deletion cmd/psweb/bitcoin/bitcoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bitcoin

import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -315,7 +316,9 @@ func SendRawTransaction(hexstring string) (string, error) {
}

// extracts Fee from PSBT
func GetFeeFromPsbt(base64string string) (float64, error) {
func GetFeeFromPsbt(psbtBytes *[]byte) (float64, error) {
base64string := base64.StdEncoding.EncodeToString(*psbtBytes)

client := BitcoinClient()
service := &Bitcoin{client}

Expand Down
4 changes: 2 additions & 2 deletions cmd/psweb/config/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func Load(dataDir string) {
// load defaults first
Config.AllowSwapRequests = true
Config.ColorScheme = "dark" // dark or light
Config.MaxHistory = 10
Config.MaxHistory = 20
Config.ElementsPass = ""
Config.BitcoinSwaps = true
Config.LocalMempool = ""
Expand Down Expand Up @@ -104,7 +104,7 @@ func Load(dataDir string) {
if err != nil {
log.Println("Error creating config file.", err)
} else {
log.Println("Config file created using defaults.")
log.Println("Config file created in", Config.DataDir)
}
return
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/psweb/config/lnd.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func SavePS() {

//key, default, new value, env key
t += setPeerswapdVariable("host", "localhost:42069", Config.RpcHost, "")
t += setPeerswapdVariable("rpchost", "localhost:42070", "", "")
t += setPeerswapdVariable("resthost", "localhost:42070", "", "")
t += setPeerswapdVariable("lnd.host", "localhost:10009", "", "LND_HOST")
t += setPeerswapdVariable("lnd.tlscertpath", filepath.Join(Config.LightningDir, "tls.cert"), "", "")
t += setPeerswapdVariable("lnd.macaroonpath", filepath.Join(Config.LightningDir, "data", "chain", "bitcoin", Config.Chain, "admin.macaroon"), "", "LND_MACAROONPATH")
Expand Down
4 changes: 0 additions & 4 deletions cmd/psweb/internet/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,24 @@ func GetLatestTag() string {
client := GetHttpClient(true)
resp, err := client.Do(req)
if err != nil {
log.Println("Error making request:", err)
return ""
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
log.Println("Failed to fetch tags. Status code:", resp.StatusCode)
return ""
}

var tags []map[string]interface{}
err = json.NewDecoder(resp.Body).Decode(&tags)
if err != nil {
log.Println("Error decoding JSON:", err)
return ""
}

if len(tags) > 0 {
latestTag := tags[0]["name"].(string)
return latestTag
} else {
log.Println("No tags found in the repository.")
return ""
}
}
2 changes: 1 addition & 1 deletion cmd/psweb/internet/mempool.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func GetNodeAlias(id string) string {
}

// fetch high priority fee rate from mempool.space
func GetFee() uint32 {
func GetFeeRate() uint32 {
if config.Config.BitcoinApi != "" {
api := config.Config.BitcoinApi + "/api/v1/fees/recommended"
req, err := http.NewRequest("GET", api, nil)
Expand Down
190 changes: 141 additions & 49 deletions cmd/psweb/ln/cln.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,60 @@ func CanRBF() bool {
return true
}

// fetch routing statistics for a channel from a given timestamp
type ListForwardsRequest struct {
Status string `json:"status"`
Index string `json:"index"`
Start uint64 `json:"start"`
}

func (r *ListForwardsRequest) Name() string {
return "listforwards"
}

type Forwarding struct {
CreatedIndex uint64 `json:"created_index"`
InChannel string `json:"in_channel"`
OutChannel string `json:"out_channel"`
OutMsat uint64 `json:"out_msat"`
FeeMsat uint64 `json:"fee_msat"`
ResolvedTime float64 `json:"resolved_time"`
}

var forwards struct {
Forwards []Forwarding `json:"forwards"`
}

// fetch routing statistics from cln
func FetchForwardingStats() {
// refresh history
client, clean, err := GetClient()
if err != nil {
return
}
defer clean()

var newForwards struct {
Forwards []Forwarding `json:"forwards"`
}

start := uint64(0)
if len(forwards.Forwards) > 0 {
// continue from the last index + 1
start = forwards.Forwards[len(forwards.Forwards)-1].CreatedIndex + 1
}

// get incremental history
client.Request(&ListForwardsRequest{
Status: "settled",
Index: "created",
Start: start,
}, &newForwards)

// append to all history
forwards.Forwards = append(forwards.Forwards, newForwards.Forwards...)
}

// get routing statistics for a channel
func GetForwardingStats(lndChannelId uint64) *ForwardingStats {
var (
result ForwardingStats
Expand All @@ -361,24 +414,6 @@ func GetForwardingStats(lndChannelId uint64) *ForwardingStats {
assistedMsat6m uint64
)

// refresh history
client, clean, err := GetClient()
if err != nil {
log.Println("GetClient:", err)
return &result
}
defer clean()

var forwards struct {
Forwards []glightning.Forwarding `json:"forwards"`
}

err = client.Request(&glightning.ListForwardsRequest{}, &forwards)
if err != nil {
log.Println(err)
return &result
}

// historic timestamps in sec
now := time.Now()
timestamp7d := float64(now.AddDate(0, 0, -7).Unix())
Expand All @@ -388,33 +423,31 @@ func GetForwardingStats(lndChannelId uint64) *ForwardingStats {
channelId := ConvertLndToClnChannelId(lndChannelId)

for _, e := range forwards.Forwards {
if e.Status == "settled" {
if e.OutChannel == channelId {
if e.ReceivedTime > timestamp6m {
amountOut6m += e.MilliSatoshiOut
feeMsat6m += e.Fee
if e.ReceivedTime > timestamp30d {
amountOut30d += e.MilliSatoshiOut
feeMsat30d += e.Fee
if e.ReceivedTime > timestamp7d {
amountOut7d += e.MilliSatoshiOut
feeMsat7d += e.Fee
log.Println(e)
}
if e.OutChannel == channelId {
if e.ResolvedTime > timestamp6m {
amountOut6m += e.OutMsat
feeMsat6m += e.FeeMsat
if e.ResolvedTime > timestamp30d {
amountOut30d += e.OutMsat
feeMsat30d += e.FeeMsat
if e.ResolvedTime > timestamp7d {
amountOut7d += e.OutMsat
feeMsat7d += e.FeeMsat
log.Println(e)
}
}
}
if e.InChannel == channelId {
if e.ReceivedTime > timestamp6m {
amountIn6m += e.MilliSatoshiOut
assistedMsat6m += e.Fee
if e.ReceivedTime > timestamp30d {
amountIn30d += e.MilliSatoshiOut
assistedMsat30d += e.Fee
if e.ReceivedTime > timestamp7d {
amountIn7d += e.MilliSatoshiOut
assistedMsat7d += e.Fee
}
}
if e.InChannel == channelId {
if e.ResolvedTime > timestamp6m {
amountIn6m += e.OutMsat
assistedMsat6m += e.FeeMsat
if e.ResolvedTime > timestamp30d {
amountIn30d += e.OutMsat
assistedMsat30d += e.FeeMsat
if e.ResolvedTime > timestamp7d {
amountIn7d += e.OutMsat
assistedMsat7d += e.FeeMsat
}
}
}
Expand All @@ -428,12 +461,71 @@ func GetForwardingStats(lndChannelId uint64) *ForwardingStats {
result.AmountIn30d = amountIn30d / 1000
result.AmountIn6m = amountIn6m / 1000

result.FeeSat7d = feeMsat7d
result.AssistedFeeSat7d = assistedMsat7d
result.FeeSat30d = feeMsat30d
result.AssistedFeeSat30d = assistedMsat30d
result.FeeSat6m = feeMsat6m
result.AssistedFeeSat6m = assistedMsat6m
result.FeeSat7d = feeMsat7d / 1000
result.AssistedFeeSat7d = assistedMsat7d / 1000
result.FeeSat30d = feeMsat30d / 1000
result.AssistedFeeSat30d = assistedMsat30d / 1000
result.FeeSat6m = feeMsat6m / 1000
result.AssistedFeeSat6m = assistedMsat6m / 1000

return &result
}

// net balance change for a channel
func GetNetFlow(lndChannelId uint64, timeStamp uint64) int64 {

netFlow := int64(0)
channelId := ConvertLndToClnChannelId(lndChannelId)
timeStampF := float64(timeStamp)

for _, e := range forwards.Forwards {
if e.InChannel == channelId {
if e.ResolvedTime > timeStampF {
netFlow -= int64(e.OutMsat)
}
}
if e.OutChannel == channelId {
if e.ResolvedTime > timeStampF {
netFlow += int64(e.OutMsat)
}
}
}
return netFlow / 1000
}

type ListPeerChannelsRequest struct {
PeerId string `json:"id,omitempty"`
}

func (r ListPeerChannelsRequest) Name() string {
return "listpeerchannels"
}

// get fees on the channel
func GetChannelInfo(client *glightning.Lightning, lndChannelId uint64, nodeId string) *ChanneInfo {
info := new(ChanneInfo)
channelId := ConvertLndToClnChannelId(lndChannelId)

var response map[string]interface{}

err := client.Request(&ListPeerChannelsRequest{
PeerId: nodeId,
}, &response)
if err != nil {
log.Println(err)
return info
}

// Iterate over channels to find ours
channels := response["channels"].([]interface{})
for _, channel := range channels {
channelMap := channel.(map[string]interface{})
if channelMap["short_channel_id"].(string) == channelId {
info.FeeBase = uint64(channelMap["fee_base_msat"].(float64))
info.FeeRate = uint64(channelMap["fee_proportional_millionths"].(float64))
break
}
}

return info
}
8 changes: 8 additions & 0 deletions cmd/psweb/ln/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ type ForwardingStats struct {
AssistedFeeSat6m uint64
}

type ChanneInfo struct {
LocalBalance uint64
RemoteBalance uint64
FeeRate uint64
FeeBase uint64
Active bool
}

func toSats(amount float64) int64 {
return int64(float64(100000000) * amount)
}
Expand Down
Loading

0 comments on commit a5cc3fc

Please sign in to comment.