mirror of
https://github.com/aljazceru/lspd.git
synced 2026-02-23 15:04:23 +01:00
lsps2: implement get_info
This commit is contained in:
3
.github/workflows/integration_tests.yaml
vendored
3
.github/workflows/integration_tests.yaml
vendored
@@ -143,7 +143,8 @@ jobs:
|
||||
matrix:
|
||||
test: [
|
||||
testLsps0GetProtocolVersions,
|
||||
testLsps2GetVersions
|
||||
testLsps2GetVersions,
|
||||
testLsps2GetInfo
|
||||
]
|
||||
implementation: [
|
||||
CLN
|
||||
|
||||
@@ -75,6 +75,9 @@ type NodeConfig struct {
|
||||
// peer is offline.
|
||||
NotificationTimeout string `json:"notificationTimeout,string"`
|
||||
|
||||
MinPaymentSizeMsat uint64 `json:"minPaymentSizeMsat,string"`
|
||||
MaxPaymentSizeMsat uint64 `json:"maxPaymentSizeMsat,string"`
|
||||
|
||||
// Set this field to connect to an LND node.
|
||||
Lnd *LndConfig `json:"lnd,omitempty"`
|
||||
|
||||
|
||||
@@ -182,4 +182,8 @@ var allTestCases = []*testCase{
|
||||
name: "testLsps2GetVersions",
|
||||
test: testLsps2GetVersions,
|
||||
},
|
||||
{
|
||||
name: "testLsps2GetInfo",
|
||||
test: testLsps2GetInfo,
|
||||
},
|
||||
}
|
||||
|
||||
70
itest/lsps2_get_info_test.go
Normal file
70
itest/lsps2_get_info_test.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package itest
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/breez/lntest"
|
||||
"github.com/breez/lspd/lsps0"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testLsps2GetInfo(p *testParams) {
|
||||
SetFeeParams(p.Lsp(), []*FeeParamSetting{
|
||||
{
|
||||
Validity: time.Second * 3600,
|
||||
MinMsat: 3000000,
|
||||
Proportional: 1000,
|
||||
},
|
||||
{
|
||||
Validity: time.Second * 2800,
|
||||
MinMsat: 2000000,
|
||||
Proportional: 800,
|
||||
},
|
||||
})
|
||||
p.BreezClient().Node().ConnectPeer(p.Lsp().LightningNode())
|
||||
|
||||
rawMsg := `{
|
||||
"method": "lsps2.get_info",
|
||||
"jsonrpc": "2.0",
|
||||
"id": "example#3cad6a54d302edba4c9ade2f7ffac098",
|
||||
"params": {
|
||||
"version": 1,
|
||||
"token": "hello"
|
||||
}
|
||||
}`
|
||||
p.BreezClient().Node().SendCustomMessage(&lntest.CustomMsgRequest{
|
||||
PeerId: hex.EncodeToString(p.Lsp().NodeId()),
|
||||
Type: lsps0.Lsps0MessageType,
|
||||
Data: []byte(rawMsg),
|
||||
})
|
||||
|
||||
resp := p.BreezClient().ReceiveCustomMessage()
|
||||
log.Print(string(resp.Data))
|
||||
assert.Equal(p.t, uint32(37913), resp.Type)
|
||||
|
||||
content := make(map[string]json.RawMessage)
|
||||
err := json.Unmarshal(resp.Data[:], &content)
|
||||
lntest.CheckError(p.t, err)
|
||||
|
||||
result := make(map[string]json.RawMessage)
|
||||
err = json.Unmarshal(content["result"], &result)
|
||||
lntest.CheckError(p.t, err)
|
||||
|
||||
menu := []*struct {
|
||||
MinFeeMsat uint64 `json:"min_fee_msat,string"`
|
||||
Proportional uint32 `json:"proportional"`
|
||||
ValidUntil string `json:"valid_until"`
|
||||
MinLifetime uint32 `json:"min_lifetime"`
|
||||
MaxClientToSelfDelay uint32 `json:"max_client_to_self_delay"`
|
||||
Promise string `json:"promise"`
|
||||
}{}
|
||||
err = json.Unmarshal(result["opening_fee_params_menu"], &menu)
|
||||
lntest.CheckError(p.t, err)
|
||||
|
||||
assert.Len(p.t, menu, 2)
|
||||
assert.Equal(p.t, uint64(2000000), menu[0].MinFeeMsat)
|
||||
assert.Equal(p.t, uint64(3000000), menu[1].MinFeeMsat)
|
||||
}
|
||||
116
lsps2/server.go
116
lsps2/server.go
@@ -2,24 +2,63 @@ package lsps2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/breez/lspd/lsps0"
|
||||
"github.com/breez/lspd/lsps0/codes"
|
||||
"github.com/breez/lspd/lsps0/status"
|
||||
"github.com/breez/lspd/shared"
|
||||
)
|
||||
|
||||
var SupportedVersion uint32 = 1
|
||||
|
||||
type GetVersionsRequest struct {
|
||||
}
|
||||
|
||||
type GetVersionsResponse struct {
|
||||
Versions []int32 `json:"versions"`
|
||||
Versions []uint32 `json:"versions"`
|
||||
}
|
||||
|
||||
type GetInfoRequest struct {
|
||||
Version uint32 `json:"version"`
|
||||
Token *string `json:"token,omitempty"`
|
||||
}
|
||||
|
||||
type GetInfoResponse struct {
|
||||
OpeningFeeParamsMenu []*OpeningFeeParams `json:"opening_fee_params_menu"`
|
||||
MinPaymentSizeMsat uint64 `json:"min_payment_size_msat,string"`
|
||||
MaxPaymentSizeMsat uint64 `json:"max_payment_size_msat,string"`
|
||||
}
|
||||
|
||||
type OpeningFeeParams struct {
|
||||
MinFeeMsat uint64 `json:"min_fee_msat,string"`
|
||||
Proportional uint32 `json:"proportional"`
|
||||
ValidUntil string `json:"valid_until"`
|
||||
MinLifetime uint32 `json:"min_lifetime"`
|
||||
MaxClientToSelfDelay uint32 `json:"max_client_to_self_delay"`
|
||||
Promise string `json:"promise"`
|
||||
}
|
||||
|
||||
type Lsps2Server interface {
|
||||
GetVersions(ctx context.Context, request *GetVersionsRequest) (*GetVersionsResponse, error)
|
||||
GetInfo(ctx context.Context, request *GetInfoRequest) (*GetInfoResponse, error)
|
||||
}
|
||||
type server struct {
|
||||
openingService shared.OpeningService
|
||||
nodesService shared.NodesService
|
||||
node *shared.Node
|
||||
}
|
||||
type server struct{}
|
||||
|
||||
func NewLsps2Server() Lsps2Server {
|
||||
return &server{}
|
||||
func NewLsps2Server(
|
||||
openingService shared.OpeningService,
|
||||
nodesService shared.NodesService,
|
||||
node *shared.Node,
|
||||
) Lsps2Server {
|
||||
return &server{
|
||||
openingService: openingService,
|
||||
nodesService: nodesService,
|
||||
node: node,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) GetVersions(
|
||||
@@ -27,7 +66,64 @@ func (s *server) GetVersions(
|
||||
request *GetVersionsRequest,
|
||||
) (*GetVersionsResponse, error) {
|
||||
return &GetVersionsResponse{
|
||||
Versions: []int32{1},
|
||||
Versions: []uint32{SupportedVersion},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *server) GetInfo(
|
||||
ctx context.Context,
|
||||
request *GetInfoRequest,
|
||||
) (*GetInfoResponse, error) {
|
||||
if request.Version != uint32(SupportedVersion) {
|
||||
return nil, status.New(codes.Code(1), "unsupported_version").Err()
|
||||
}
|
||||
|
||||
if request.Token == nil || *request.Token == "" {
|
||||
return nil, status.New(codes.Code(2), "unrecognized_or_stale_token").Err()
|
||||
}
|
||||
|
||||
node, err := s.nodesService.GetNode(*request.Token)
|
||||
if err == shared.ErrNodeNotFound {
|
||||
return nil, status.New(codes.Code(2), "unrecognized_or_stale_token").Err()
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("Lsps2Server.GetInfo: nodesService.GetNode(%s) err: %v", *request.Token, err)
|
||||
return nil, status.New(codes.InternalError, "internal error").Err()
|
||||
}
|
||||
if node.NodeConfig.NodePubkey != s.node.NodeConfig.NodePubkey {
|
||||
log.Printf(
|
||||
"Lsps2Server.GetInfo: Got token '%s' on node '%s', but was meant for node '%s'",
|
||||
*request.Token,
|
||||
s.node.NodeConfig.NodePubkey,
|
||||
node.NodeConfig.NodePubkey,
|
||||
)
|
||||
return nil, status.New(codes.Code(2), "unrecognized_or_stale_token").Err()
|
||||
}
|
||||
|
||||
m, err := s.openingService.GetFeeParamsMenu(*request.Token, node.PrivateKey)
|
||||
if err == shared.ErrNodeNotFound {
|
||||
return nil, status.New(codes.Code(2), "unrecognized_or_stale_token").Err()
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("Lsps2Server.GetInfo: openingService.GetFeeParamsMenu(%s) err: %v", *request.Token, err)
|
||||
return nil, status.New(codes.InternalError, "internal error").Err()
|
||||
}
|
||||
|
||||
menu := []*OpeningFeeParams{}
|
||||
for _, p := range m {
|
||||
menu = append(menu, &OpeningFeeParams{
|
||||
MinFeeMsat: p.MinFeeMsat,
|
||||
Proportional: p.Proportional,
|
||||
ValidUntil: p.ValidUntil,
|
||||
MinLifetime: p.MinLifetime,
|
||||
MaxClientToSelfDelay: p.MaxClientToSelfDelay,
|
||||
Promise: p.Promise,
|
||||
})
|
||||
}
|
||||
return &GetInfoResponse{
|
||||
OpeningFeeParamsMenu: menu,
|
||||
MinPaymentSizeMsat: node.NodeConfig.MinPaymentSizeMsat,
|
||||
MaxPaymentSizeMsat: node.NodeConfig.MaxPaymentSizeMsat,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -47,6 +143,16 @@ func RegisterLsps2Server(s lsps0.ServiceRegistrar, l Lsps2Server) {
|
||||
return srv.(Lsps2Server).GetVersions(ctx, in)
|
||||
},
|
||||
},
|
||||
{
|
||||
MethodName: "lsps2.get_info",
|
||||
Handler: func(srv interface{}, ctx context.Context, dec func(interface{}) error) (interface{}, error) {
|
||||
in := new(GetInfoRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return srv.(Lsps2Server).GetInfo(ctx, in)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
l,
|
||||
|
||||
145
lsps2/server_test.go
Normal file
145
lsps2/server_test.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package lsps2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/breez/lspd/config"
|
||||
"github.com/breez/lspd/lsps0/status"
|
||||
"github.com/breez/lspd/shared"
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type mockNodesService struct {
|
||||
node *shared.Node
|
||||
err error
|
||||
}
|
||||
|
||||
func (m *mockNodesService) GetNode(token string) (*shared.Node, error) {
|
||||
return m.node, m.err
|
||||
}
|
||||
|
||||
func (m *mockNodesService) GetNodes() []*shared.Node {
|
||||
return []*shared.Node{m.node}
|
||||
}
|
||||
|
||||
type mockOpeningService struct {
|
||||
menu []*shared.OpeningFeeParams
|
||||
err error
|
||||
valid bool
|
||||
}
|
||||
|
||||
func (m *mockOpeningService) GetFeeParamsMenu(
|
||||
token string,
|
||||
privateKey *btcec.PrivateKey,
|
||||
) ([]*shared.OpeningFeeParams, error) {
|
||||
return m.menu, m.err
|
||||
}
|
||||
|
||||
func (m *mockOpeningService) ValidateOpeningFeeParams(
|
||||
params *shared.OpeningFeeParams,
|
||||
publicKey *btcec.PublicKey,
|
||||
) bool {
|
||||
return m.valid
|
||||
}
|
||||
|
||||
var token = "blah"
|
||||
var node = &shared.Node{
|
||||
NodeConfig: &config.NodeConfig{
|
||||
MinPaymentSizeMsat: 123,
|
||||
MaxPaymentSizeMsat: 456,
|
||||
},
|
||||
}
|
||||
|
||||
func Test_GetInfo_UnsupportedVersion(t *testing.T) {
|
||||
n := &mockNodesService{}
|
||||
o := &mockOpeningService{}
|
||||
s := NewLsps2Server(o, n, nil)
|
||||
_, err := s.GetInfo(context.Background(), &GetInfoRequest{
|
||||
Version: 2,
|
||||
Token: &token,
|
||||
})
|
||||
|
||||
st := status.Convert(err)
|
||||
assert.Equal(t, uint32(1), uint32(st.Code))
|
||||
assert.Equal(t, "unsupported_version", st.Message)
|
||||
}
|
||||
|
||||
func Test_GetInfo_InvalidToken(t *testing.T) {
|
||||
n := &mockNodesService{
|
||||
err: shared.ErrNodeNotFound,
|
||||
}
|
||||
o := &mockOpeningService{}
|
||||
s := NewLsps2Server(o, n, nil)
|
||||
_, err := s.GetInfo(context.Background(), &GetInfoRequest{
|
||||
Version: 1,
|
||||
Token: &token,
|
||||
})
|
||||
|
||||
st := status.Convert(err)
|
||||
assert.Equal(t, uint32(2), uint32(st.Code))
|
||||
assert.Equal(t, "unrecognized_or_stale_token", st.Message)
|
||||
}
|
||||
|
||||
func Test_GetInfo_EmptyMenu(t *testing.T) {
|
||||
n := &mockNodesService{node: node}
|
||||
o := &mockOpeningService{menu: []*shared.OpeningFeeParams{}}
|
||||
s := NewLsps2Server(o, n, node)
|
||||
resp, err := s.GetInfo(context.Background(), &GetInfoRequest{
|
||||
Version: 1,
|
||||
Token: &token,
|
||||
})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, []*OpeningFeeParams{}, resp.OpeningFeeParamsMenu)
|
||||
assert.Equal(t, node.NodeConfig.MinPaymentSizeMsat, resp.MinPaymentSizeMsat)
|
||||
assert.Equal(t, node.NodeConfig.MaxPaymentSizeMsat, resp.MaxPaymentSizeMsat)
|
||||
}
|
||||
|
||||
func Test_GetInfo_PopulatedMenu_Ordered(t *testing.T) {
|
||||
n := &mockNodesService{node: node}
|
||||
o := &mockOpeningService{menu: []*shared.OpeningFeeParams{
|
||||
{
|
||||
MinFeeMsat: 1,
|
||||
Proportional: 2,
|
||||
ValidUntil: "a",
|
||||
MinLifetime: 3,
|
||||
MaxClientToSelfDelay: 4,
|
||||
Promise: "b",
|
||||
},
|
||||
{
|
||||
MinFeeMsat: 5,
|
||||
Proportional: 6,
|
||||
ValidUntil: "c",
|
||||
MinLifetime: 7,
|
||||
MaxClientToSelfDelay: 8,
|
||||
Promise: "d",
|
||||
},
|
||||
}}
|
||||
s := NewLsps2Server(o, n, node)
|
||||
resp, err := s.GetInfo(context.Background(), &GetInfoRequest{
|
||||
Version: 1,
|
||||
Token: &token,
|
||||
})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, resp.OpeningFeeParamsMenu, 2)
|
||||
|
||||
assert.Equal(t, uint64(1), resp.OpeningFeeParamsMenu[0].MinFeeMsat)
|
||||
assert.Equal(t, uint32(2), resp.OpeningFeeParamsMenu[0].Proportional)
|
||||
assert.Equal(t, "a", resp.OpeningFeeParamsMenu[0].ValidUntil)
|
||||
assert.Equal(t, uint32(3), resp.OpeningFeeParamsMenu[0].MinLifetime)
|
||||
assert.Equal(t, uint32(4), resp.OpeningFeeParamsMenu[0].MaxClientToSelfDelay)
|
||||
assert.Equal(t, "b", resp.OpeningFeeParamsMenu[0].Promise)
|
||||
|
||||
assert.Equal(t, uint64(5), resp.OpeningFeeParamsMenu[1].MinFeeMsat)
|
||||
assert.Equal(t, uint32(6), resp.OpeningFeeParamsMenu[1].Proportional)
|
||||
assert.Equal(t, "c", resp.OpeningFeeParamsMenu[1].ValidUntil)
|
||||
assert.Equal(t, uint32(7), resp.OpeningFeeParamsMenu[1].MinLifetime)
|
||||
assert.Equal(t, uint32(8), resp.OpeningFeeParamsMenu[1].MaxClientToSelfDelay)
|
||||
assert.Equal(t, "d", resp.OpeningFeeParamsMenu[1].Promise)
|
||||
|
||||
assert.Equal(t, node.NodeConfig.MinPaymentSizeMsat, resp.MinPaymentSizeMsat)
|
||||
assert.Equal(t, node.NodeConfig.MaxPaymentSizeMsat, resp.MaxPaymentSizeMsat)
|
||||
}
|
||||
2
main.go
2
main.go
@@ -125,7 +125,7 @@ func main() {
|
||||
go msgClient.Start()
|
||||
msgServer := lsps0.NewServer()
|
||||
protocolServer := lsps0.NewProtocolServer([]uint32{2})
|
||||
lsps2Server := lsps2.NewLsps2Server()
|
||||
lsps2Server := lsps2.NewLsps2Server(openingService, nodesService, node)
|
||||
lsps0.RegisterProtocolServer(msgServer, protocolServer)
|
||||
lsps2.RegisterLsps2Server(msgServer, lsps2Server)
|
||||
msgClient.WaitStarted()
|
||||
|
||||
Reference in New Issue
Block a user