diff --git a/metricsDatasource.js b/metricsDatasource.js index 5e1bdffa..778c781d 100644 --- a/metricsDatasource.js +++ b/metricsDatasource.js @@ -3,6 +3,7 @@ import { BalanceEvent } from "./build/src/services/storage/entity/BalanceEvent.j import { ChannelBalanceEvent } from "./build/src/services/storage/entity/ChannelsBalanceEvent.js" import { ChannelRouting } from "./build/src/services/storage/entity/ChannelRouting.js" import { RootOperation } from "./build/src/services/storage/entity/RootOperation.js" +import { ChannelEvent } from "./build/src/services/storage/entity/ChannelEvent.js" import { LndMetrics1703170330183 } from './build/src/services/storage/migrations/1703170330183-lnd_metrics.js' import { ChannelRouting1709316653538 } from './build/src/services/storage/migrations/1709316653538-channel_routing.js' import { HtlcCount1724266887195 } from './build/src/services/storage/migrations/1724266887195-htlc_count.js' @@ -11,8 +12,8 @@ import { BalanceEvents1724860966825 } from './build/src/services/storage/migrati export default new DataSource({ type: "sqlite", database: "metrics.sqlite", - entities: [BalanceEvent, ChannelBalanceEvent, ChannelRouting, RootOperation], + entities: [BalanceEvent, ChannelBalanceEvent, ChannelRouting, RootOperation, ChannelEvent], migrations: [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825] }); -//npx typeorm migration:generate ./src/services/storage/migrations/root_ops_time -d ./metricsDatasource.js \ No newline at end of file +//npx typeorm migration:generate ./src/services/storage/migrations/channel_events -d ./metricsDatasource.js \ No newline at end of file diff --git a/proto/autogenerated/client.md b/proto/autogenerated/client.md index 2596a38e..16aef4db 100644 --- a/proto/autogenerated/client.md +++ b/proto/autogenerated/client.md @@ -133,6 +133,11 @@ The nostr server will send back a message response, and inside the body there wi - This methods has an __empty__ __request__ body - output: [LiveUserOperation](#LiveUserOperation) +- GetLndForwardingMetrics + - auth type: __Metrics__ + - input: [LndMetricsRequest](#LndMetricsRequest) + - output: [LndForwardingMetrics](#LndForwardingMetrics) + - GetLndMetrics - auth type: __Metrics__ - input: [LndMetricsRequest](#LndMetricsRequest) @@ -567,6 +572,13 @@ The nostr server will send back a message response, and inside the body there wi - This methods has an __empty__ __request__ body - output: [LiveUserOperation](#LiveUserOperation) +- GetLndForwardingMetrics + - auth type: __Metrics__ + - http method: __post__ + - http route: __/api/reports/lnd/forwarding__ + - input: [LndMetricsRequest](#LndMetricsRequest) + - output: [LndForwardingMetrics](#LndForwardingMetrics) + - GetLndMetrics - auth type: __Metrics__ - http method: __post__ @@ -1210,6 +1222,18 @@ The nostr server will send back a message response, and inside the body there wi ### LndChannels - __open_channels__: ARRAY of: _[OpenChannel](#OpenChannel)_ +### LndForwardingEvent + - __amt_in__: _number_ + - __amt_out__: _number_ + - __at_unix__: _number_ + - __chan_id_in__: _string_ + - __chan_id_out__: _string_ + - __fee__: _number_ + +### LndForwardingMetrics + - __events__: ARRAY of: _[LndForwardingEvent](#LndForwardingEvent)_ + - __total_fees__: _number_ + ### LndGetInfoRequest - __nodeId__: _number_ @@ -1316,6 +1340,7 @@ The nostr server will send back a message response, and inside the body there wi - __capacity__: _number_ - __channel_id__: _string_ - __channel_point__: _string_ + - __inactive_since_unix__: _number_ - __label__: _string_ - __lifetime__: _number_ - __local_balance__: _number_ diff --git a/proto/autogenerated/go/http_client.go b/proto/autogenerated/go/http_client.go index 1f29f872..bd9a32f0 100644 --- a/proto/autogenerated/go/http_client.go +++ b/proto/autogenerated/go/http_client.go @@ -85,6 +85,7 @@ type Client struct { GetLNURLChannelLink func() (*LnurlLinkResponse, error) GetLiveDebitRequests func() (*LiveDebitRequest, error) GetLiveUserOperations func() (*LiveUserOperation, error) + GetLndForwardingMetrics func(req LndMetricsRequest) (*LndForwardingMetrics, error) GetLndMetrics func(req LndMetricsRequest) (*LndMetrics, error) GetLnurlPayInfo func(query GetLnurlPayInfo_Query) (*LnurlPayInfoResponse, error) GetLnurlPayLink func() (*LnurlLinkResponse, error) @@ -906,6 +907,35 @@ func NewClient(params ClientParams) *Client { }, // server streaming method: GetLiveDebitRequests not implemented // server streaming method: GetLiveUserOperations not implemented + GetLndForwardingMetrics: func(req LndMetricsRequest) (*LndForwardingMetrics, error) { + auth, err := params.RetrieveMetricsAuth() + if err != nil { + return nil, err + } + finalRoute := "/api/reports/lnd/forwarding" + body, err := json.Marshal(req) + if err != nil { + return nil, err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return nil, err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return nil, err + } + if result.Status == "ERROR" { + return nil, fmt.Errorf(result.Reason) + } + res := LndForwardingMetrics{} + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, err + } + return &res, nil + }, GetLndMetrics: func(req LndMetricsRequest) (*LndMetrics, error) { auth, err := params.RetrieveMetricsAuth() if err != nil { diff --git a/proto/autogenerated/go/types.go b/proto/autogenerated/go/types.go index 68d35a25..9a1b63ff 100644 --- a/proto/autogenerated/go/types.go +++ b/proto/autogenerated/go/types.go @@ -361,6 +361,18 @@ type LiveUserOperation struct { type LndChannels struct { Open_channels []OpenChannel `json:"open_channels"` } +type LndForwardingEvent struct { + Amt_in int64 `json:"amt_in"` + Amt_out int64 `json:"amt_out"` + At_unix int64 `json:"at_unix"` + Chan_id_in string `json:"chan_id_in"` + Chan_id_out string `json:"chan_id_out"` + Fee int64 `json:"fee"` +} +type LndForwardingMetrics struct { + Events []LndForwardingEvent `json:"events"` + Total_fees int64 `json:"total_fees"` +} type LndGetInfoRequest struct { Nodeid int64 `json:"nodeId"` } @@ -463,15 +475,16 @@ type OfferInvoices struct { Invoices []OfferInvoice `json:"invoices"` } type OpenChannel struct { - Active bool `json:"active"` - Capacity int64 `json:"capacity"` - Channel_id string `json:"channel_id"` - Channel_point string `json:"channel_point"` - Label string `json:"label"` - Lifetime int64 `json:"lifetime"` - Local_balance int64 `json:"local_balance"` - Policy *ChannelPolicy `json:"policy"` - Remote_balance int64 `json:"remote_balance"` + Active bool `json:"active"` + Capacity int64 `json:"capacity"` + Channel_id string `json:"channel_id"` + Channel_point string `json:"channel_point"` + Inactive_since_unix int64 `json:"inactive_since_unix"` + Label string `json:"label"` + Lifetime int64 `json:"lifetime"` + Local_balance int64 `json:"local_balance"` + Policy *ChannelPolicy `json:"policy"` + Remote_balance int64 `json:"remote_balance"` } type OpenChannelRequest struct { Close_address string `json:"close_address"` diff --git a/proto/autogenerated/ts/express_server.ts b/proto/autogenerated/ts/express_server.ts index 7a3116ef..8e6e04f2 100644 --- a/proto/autogenerated/ts/express_server.ts +++ b/proto/autogenerated/ts/express_server.ts @@ -996,6 +996,28 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }) + if (!opts.allowNotImplementedMethods && !methods.GetLndForwardingMetrics) throw new Error('method: GetLndForwardingMetrics is not implemented') + app.post('/api/reports/lnd/forwarding', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'GetLndForwardingMetrics', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.GetLndForwardingMetrics) throw new Error('method: GetLndForwardingMetrics is not implemented') + const authContext = await opts.MetricsAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.LndMetricsRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + const response = await methods.GetLndForwardingMetrics({rpcName:'GetLndForwardingMetrics', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) if (!opts.allowNotImplementedMethods && !methods.GetLndMetrics) throw new Error('method: GetLndMetrics is not implemented') app.post('/api/reports/lnd', async (req, res) => { const info: Types.RequestInfo = { rpcName: 'GetLndMetrics', batch: false, nostr: false, batchSize: 0} diff --git a/proto/autogenerated/ts/http_client.ts b/proto/autogenerated/ts/http_client.ts index 0afa72aa..5750aa3e 100644 --- a/proto/autogenerated/ts/http_client.ts +++ b/proto/autogenerated/ts/http_client.ts @@ -404,6 +404,20 @@ export default (params: ClientParams) => ({ }, GetLiveDebitRequests: async (cb: (v:ResultError | ({ status: 'OK' }& Types.LiveDebitRequest)) => void): Promise => { throw new Error('http streams are not supported')}, GetLiveUserOperations: async (cb: (v:ResultError | ({ status: 'OK' }& Types.LiveUserOperation)) => void): Promise => { throw new Error('http streams are not supported')}, + GetLndForwardingMetrics: async (request: Types.LndMetricsRequest): Promise => { + const auth = await params.retrieveMetricsAuth() + if (auth === null) throw new Error('retrieveMetricsAuth() returned null') + let finalRoute = '/api/reports/lnd/forwarding' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LndForwardingMetricsValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, GetLndMetrics: async (request: Types.LndMetricsRequest): Promise => { const auth = await params.retrieveMetricsAuth() if (auth === null) throw new Error('retrieveMetricsAuth() returned null') diff --git a/proto/autogenerated/ts/nostr_client.ts b/proto/autogenerated/ts/nostr_client.ts index 6813815d..a08f4015 100644 --- a/proto/autogenerated/ts/nostr_client.ts +++ b/proto/autogenerated/ts/nostr_client.ts @@ -349,6 +349,21 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ return cb({ status: 'ERROR', reason: 'invalid response' }) }) }, + GetLndForwardingMetrics: async (request: Types.LndMetricsRequest): Promise => { + const auth = await params.retrieveNostrMetricsAuth() + if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'GetLndForwardingMetrics',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + const result = data + if(!params.checkResult) return { status: 'OK', ...result } + const error = Types.LndForwardingMetricsValidate(result) + if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message } + } + return { status: 'ERROR', reason: 'invalid response' } + }, GetLndMetrics: async (request: Types.LndMetricsRequest): Promise => { const auth = await params.retrieveNostrMetricsAuth() if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null') diff --git a/proto/autogenerated/ts/nostr_transport.ts b/proto/autogenerated/ts/nostr_transport.ts index 55553eb6..5e9ea211 100644 --- a/proto/autogenerated/ts/nostr_transport.ts +++ b/proto/autogenerated/ts/nostr_transport.ts @@ -741,6 +741,22 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { }}) }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } break + case 'GetLndForwardingMetrics': + try { + if (!methods.GetLndForwardingMetrics) throw new Error('method: GetLndForwardingMetrics is not implemented') + const authContext = await opts.NostrMetricsAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.LndMetricsRequestValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + const response = await methods.GetLndForwardingMetrics({rpcName:'GetLndForwardingMetrics', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK', ...response}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break case 'GetLndMetrics': try { if (!methods.GetLndMetrics) throw new Error('method: GetLndMetrics is not implemented') diff --git a/proto/autogenerated/ts/types.ts b/proto/autogenerated/ts/types.ts index dff4ae99..9dc61dbd 100644 --- a/proto/autogenerated/ts/types.ts +++ b/proto/autogenerated/ts/types.ts @@ -28,8 +28,8 @@ export type MetricsContext = { app_id: string operator_id: string } -export type MetricsMethodInputs = GetAppsMetrics_Input | GetBundleMetrics_Input | GetErrorStats_Input | GetLndMetrics_Input | GetProvidersDisruption_Input | GetSingleBundleMetrics_Input | GetSingleUsageMetrics_Input | GetUsageMetrics_Input | PingSubProcesses_Input | ResetMetricsStorages_Input | SubmitWebRtcMessage_Input | ZipMetricsStorages_Input -export type MetricsMethodOutputs = GetAppsMetrics_Output | GetBundleMetrics_Output | GetErrorStats_Output | GetLndMetrics_Output | GetProvidersDisruption_Output | GetSingleBundleMetrics_Output | GetSingleUsageMetrics_Output | GetUsageMetrics_Output | PingSubProcesses_Output | ResetMetricsStorages_Output | SubmitWebRtcMessage_Output | ZipMetricsStorages_Output +export type MetricsMethodInputs = GetAppsMetrics_Input | GetBundleMetrics_Input | GetErrorStats_Input | GetLndForwardingMetrics_Input | GetLndMetrics_Input | GetProvidersDisruption_Input | GetSingleBundleMetrics_Input | GetSingleUsageMetrics_Input | GetUsageMetrics_Input | PingSubProcesses_Input | ResetMetricsStorages_Input | SubmitWebRtcMessage_Input | ZipMetricsStorages_Input +export type MetricsMethodOutputs = GetAppsMetrics_Output | GetBundleMetrics_Output | GetErrorStats_Output | GetLndForwardingMetrics_Output | GetLndMetrics_Output | GetProvidersDisruption_Output | GetSingleBundleMetrics_Output | GetSingleUsageMetrics_Output | GetUsageMetrics_Output | PingSubProcesses_Output | ResetMetricsStorages_Output | SubmitWebRtcMessage_Output | ZipMetricsStorages_Output export type UserContext = { app_id: string app_user_id: string @@ -132,6 +132,9 @@ export type GetLiveDebitRequests_Output = ResultError | { status: 'OK' } export type GetLiveUserOperations_Input = {rpcName:'GetLiveUserOperations', cb:(res: LiveUserOperation, err:Error|null)=> void} export type GetLiveUserOperations_Output = ResultError | { status: 'OK' } +export type GetLndForwardingMetrics_Input = {rpcName:'GetLndForwardingMetrics', req: LndMetricsRequest} +export type GetLndForwardingMetrics_Output = ResultError | ({ status: 'OK' } & LndForwardingMetrics) + export type GetLndMetrics_Input = {rpcName:'GetLndMetrics', req: LndMetricsRequest} export type GetLndMetrics_Output = ResultError | ({ status: 'OK' } & LndMetrics) @@ -338,6 +341,7 @@ export type ServerMethods = { GetLNURLChannelLink?: (req: GetLNURLChannelLink_Input & {ctx: UserContext }) => Promise GetLiveDebitRequests?: (req: GetLiveDebitRequests_Input & {ctx: UserContext }) => Promise GetLiveUserOperations?: (req: GetLiveUserOperations_Input & {ctx: UserContext }) => Promise + GetLndForwardingMetrics?: (req: GetLndForwardingMetrics_Input & {ctx: MetricsContext }) => Promise GetLndMetrics?: (req: GetLndMetrics_Input & {ctx: MetricsContext }) => Promise GetLnurlPayInfo?: (req: GetLnurlPayInfo_Input & {ctx: GuestContext }) => Promise GetLnurlPayLink?: (req: GetLnurlPayLink_Input & {ctx: UserContext }) => Promise @@ -2049,6 +2053,77 @@ export const LndChannelsValidate = (o?: LndChannels, opts: LndChannelsOptions = return null } +export type LndForwardingEvent = { + amt_in: number + amt_out: number + at_unix: number + chan_id_in: string + chan_id_out: string + fee: number +} +export const LndForwardingEventOptionalFields: [] = [] +export type LndForwardingEventOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + amt_in_CustomCheck?: (v: number) => boolean + amt_out_CustomCheck?: (v: number) => boolean + at_unix_CustomCheck?: (v: number) => boolean + chan_id_in_CustomCheck?: (v: string) => boolean + chan_id_out_CustomCheck?: (v: string) => boolean + fee_CustomCheck?: (v: number) => boolean +} +export const LndForwardingEventValidate = (o?: LndForwardingEvent, opts: LndForwardingEventOptions = {}, path: string = 'LndForwardingEvent::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.amt_in !== 'number') return new Error(`${path}.amt_in: is not a number`) + if (opts.amt_in_CustomCheck && !opts.amt_in_CustomCheck(o.amt_in)) return new Error(`${path}.amt_in: custom check failed`) + + if (typeof o.amt_out !== 'number') return new Error(`${path}.amt_out: is not a number`) + if (opts.amt_out_CustomCheck && !opts.amt_out_CustomCheck(o.amt_out)) return new Error(`${path}.amt_out: custom check failed`) + + if (typeof o.at_unix !== 'number') return new Error(`${path}.at_unix: is not a number`) + if (opts.at_unix_CustomCheck && !opts.at_unix_CustomCheck(o.at_unix)) return new Error(`${path}.at_unix: custom check failed`) + + if (typeof o.chan_id_in !== 'string') return new Error(`${path}.chan_id_in: is not a string`) + if (opts.chan_id_in_CustomCheck && !opts.chan_id_in_CustomCheck(o.chan_id_in)) return new Error(`${path}.chan_id_in: custom check failed`) + + if (typeof o.chan_id_out !== 'string') return new Error(`${path}.chan_id_out: is not a string`) + if (opts.chan_id_out_CustomCheck && !opts.chan_id_out_CustomCheck(o.chan_id_out)) return new Error(`${path}.chan_id_out: custom check failed`) + + if (typeof o.fee !== 'number') return new Error(`${path}.fee: is not a number`) + if (opts.fee_CustomCheck && !opts.fee_CustomCheck(o.fee)) return new Error(`${path}.fee: custom check failed`) + + return null +} + +export type LndForwardingMetrics = { + events: LndForwardingEvent[] + total_fees: number +} +export const LndForwardingMetricsOptionalFields: [] = [] +export type LndForwardingMetricsOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + events_ItemOptions?: LndForwardingEventOptions + events_CustomCheck?: (v: LndForwardingEvent[]) => boolean + total_fees_CustomCheck?: (v: number) => boolean +} +export const LndForwardingMetricsValidate = (o?: LndForwardingMetrics, opts: LndForwardingMetricsOptions = {}, path: string = 'LndForwardingMetrics::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (!Array.isArray(o.events)) return new Error(`${path}.events: is not an array`) + for (let index = 0; index < o.events.length; index++) { + const eventsErr = LndForwardingEventValidate(o.events[index], opts.events_ItemOptions, `${path}.events[${index}]`) + if (eventsErr !== null) return eventsErr + } + if (opts.events_CustomCheck && !opts.events_CustomCheck(o.events)) return new Error(`${path}.events: custom check failed`) + + if (typeof o.total_fees !== 'number') return new Error(`${path}.total_fees: is not a number`) + if (opts.total_fees_CustomCheck && !opts.total_fees_CustomCheck(o.total_fees)) return new Error(`${path}.total_fees: custom check failed`) + + return null +} + export type LndGetInfoRequest = { nodeId: number } @@ -2676,6 +2751,7 @@ export type OpenChannel = { capacity: number channel_id: string channel_point: string + inactive_since_unix: number label: string lifetime: number local_balance: number @@ -2690,6 +2766,7 @@ export type OpenChannelOptions = OptionsBaseMessage & { capacity_CustomCheck?: (v: number) => boolean channel_id_CustomCheck?: (v: string) => boolean channel_point_CustomCheck?: (v: string) => boolean + inactive_since_unix_CustomCheck?: (v: number) => boolean label_CustomCheck?: (v: string) => boolean lifetime_CustomCheck?: (v: number) => boolean local_balance_CustomCheck?: (v: number) => boolean @@ -2712,6 +2789,9 @@ export const OpenChannelValidate = (o?: OpenChannel, opts: OpenChannelOptions = if (typeof o.channel_point !== 'string') return new Error(`${path}.channel_point: is not a string`) if (opts.channel_point_CustomCheck && !opts.channel_point_CustomCheck(o.channel_point)) return new Error(`${path}.channel_point: custom check failed`) + if (typeof o.inactive_since_unix !== 'number') return new Error(`${path}.inactive_since_unix: is not a number`) + if (opts.inactive_since_unix_CustomCheck && !opts.inactive_since_unix_CustomCheck(o.inactive_since_unix)) return new Error(`${path}.inactive_since_unix: custom check failed`) + if (typeof o.label !== 'string') return new Error(`${path}.label: is not a string`) if (opts.label_CustomCheck && !opts.label_CustomCheck(o.label)) return new Error(`${path}.label: custom check failed`) diff --git a/proto/service/methods.proto b/proto/service/methods.proto index 7ebe175f..21f0a9d6 100644 --- a/proto/service/methods.proto +++ b/proto/service/methods.proto @@ -221,6 +221,15 @@ service LightningPub { option (http_route) = "/api/reports/lnd"; option (nostr) = true; } + + rpc GetLndForwardingMetrics(structs.LndMetricsRequest) returns (structs.LndForwardingMetrics) { + option (auth_type) = "Metrics"; + option (http_method) = "post"; + option (http_route) = "/api/reports/lnd/forwarding"; + option (nostr) = true; + } + + rpc SubmitWebRtcMessage(structs.WebRtcMessage) returns (structs.WebRtcAnswer) { option (auth_type) = "Metrics"; option (http_method) = "post"; diff --git a/proto/service/structs.proto b/proto/service/structs.proto index 068576c5..430198c5 100644 --- a/proto/service/structs.proto +++ b/proto/service/structs.proto @@ -184,12 +184,13 @@ message OpenChannel { string channel_id = 1; int64 capacity = 2; bool active = 3; - int64 lifetime =4 ; + int64 lifetime =4; int64 local_balance=5; int64 remote_balance = 6; string label = 7; string channel_point = 8; optional ChannelPolicy policy = 9; + int64 inactive_since_unix = 10; } message ClosedChannel { string channel_id = 1; @@ -213,6 +214,20 @@ message RootOperation { int64 created_at_unix = 4; } +message LndForwardingEvent { + string chan_id_in = 1; + string chan_id_out = 2; + int64 amt_in = 3; + int64 amt_out = 4; + int64 fee = 5; + int64 at_unix = 6; +} + +message LndForwardingMetrics { + int64 total_fees = 1; + repeated LndForwardingEvent events = 2; +} + message LndNodeMetrics { repeated GraphPoint chain_balance = 1; repeated GraphPoint channel_balance = 2; diff --git a/src/services/lnd/lnd.ts b/src/services/lnd/lnd.ts index df038b32..6c5112de 100644 --- a/src/services/lnd/lnd.ts +++ b/src/services/lnd/lnd.ts @@ -8,12 +8,12 @@ import { LightningClient } from '../../../proto/lnd/lightning.client.js' import { InvoicesClient } from '../../../proto/lnd/invoices.client.js' import { RouterClient } from '../../../proto/lnd/router.client.js' import { ChainNotifierClient } from '../../../proto/lnd/chainnotifier.client.js' -import { GetInfoResponse, AddressType, NewAddressResponse, AddInvoiceResponse, Invoice_InvoiceState, PayReq, Payment_PaymentStatus, Payment, PaymentFailureReason, SendCoinsResponse, EstimateFeeResponse, ChannelBalanceResponse, TransactionDetails, ListChannelsResponse, ClosedChannelsResponse, PendingChannelsResponse, ForwardingHistoryResponse, CoinSelectionStrategy, OpenStatusUpdate, CloseStatusUpdate, PendingUpdate } from '../../../proto/lnd/lightning.js' +import { GetInfoResponse, AddressType, NewAddressResponse, AddInvoiceResponse, Invoice_InvoiceState, PayReq, Payment_PaymentStatus, Payment, PaymentFailureReason, SendCoinsResponse, EstimateFeeResponse, ChannelBalanceResponse, TransactionDetails, ListChannelsResponse, ClosedChannelsResponse, PendingChannelsResponse, ForwardingHistoryResponse, CoinSelectionStrategy, OpenStatusUpdate, CloseStatusUpdate, PendingUpdate, ChannelEventUpdate_UpdateType } from '../../../proto/lnd/lightning.js' import { OpenChannelReq } from './openChannelReq.js'; import { AddInvoiceReq } from './addInvoiceReq.js'; import { PayInvoiceReq } from './payInvoiceReq.js'; import { SendCoinsReq } from './sendCoinsReq.js'; -import { LndSettings, AddressPaidCb, InvoicePaidCb, NodeInfo, Invoice, DecodedInvoice, PaidInvoice, NewBlockCb, HtlcCb, BalanceInfo } from './settings.js'; +import { LndSettings, AddressPaidCb, InvoicePaidCb, NodeInfo, Invoice, DecodedInvoice, PaidInvoice, NewBlockCb, HtlcCb, BalanceInfo, ChannelEventCb } from './settings.js'; import { ERROR, getLogger } from '../helpers/logger.js'; import { HtlcEvent_EventType } from '../../../proto/lnd/router.js'; import { LiquidityProvider, LiquidityRequest } from '../main/liquidityProvider.js'; @@ -38,17 +38,19 @@ export default class { invoicePaidCb: InvoicePaidCb newBlockCb: NewBlockCb htlcCb: HtlcCb + channelEventCb: ChannelEventCb log = getLogger({ component: 'lndManager' }) outgoingOpsLocked = false liquidProvider: LiquidityProvider utils: Utils - constructor(settings: LndSettings, liquidProvider: LiquidityProvider, utils: Utils, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb, newBlockCb: NewBlockCb, htlcCb: HtlcCb) { + constructor(settings: LndSettings, liquidProvider: LiquidityProvider, utils: Utils, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb, newBlockCb: NewBlockCb, htlcCb: HtlcCb, channelEventCb: ChannelEventCb) { this.settings = settings this.utils = utils this.addressPaidCb = addressPaidCb this.invoicePaidCb = invoicePaidCb this.newBlockCb = newBlockCb this.htlcCb = htlcCb + this.channelEventCb = channelEventCb const { lndAddr, lndCertPath, lndMacaroonPath } = this.settings.mainNode const lndCert = fs.readFileSync(lndCertPath); const macaroon = fs.readFileSync(lndMacaroonPath).toString('hex'); @@ -97,6 +99,7 @@ export default class { this.SubscribeInvoicePaid() this.SubscribeNewBlock() this.SubscribeHtlcEvents() + this.SubscribeChannelEvents() const now = Date.now() return new Promise((res, rej) => { const interval = setInterval(async () => { @@ -168,6 +171,20 @@ export default class { }, deadLndRetrySeconds * 1000) } + async SubscribeChannelEvents() { + const stream = this.lightning.subscribeChannelEvents({}, { abort: this.abortController.signal }) + stream.responses.onMessage(async channel => { + const channels = await this.ListChannels() + this.channelEventCb(channel, channels.channels) + }) + stream.responses.onError(error => { + this.log("Error with subscribeChannelEvents stream") + }) + stream.responses.onComplete(() => { + this.log("subscribeChannelEvents stream closed") + }) + } + async SubscribeHtlcEvents() { const stream = this.router.subscribeHtlcEvents({}, { abort: this.abortController.signal }) stream.responses.onMessage(htlc => { @@ -448,8 +465,8 @@ export default class { return { confirmedBalance: Number(confirmedBalance), unconfirmedBalance: Number(unconfirmedBalance), totalBalance: Number(totalBalance), channelsBalance } } - async GetForwardingHistory(indexOffset: number, startTime = 0): Promise { - const { response } = await this.lightning.forwardingHistory({ indexOffset, numMaxEvents: 0, startTime: BigInt(startTime), endTime: 0n, peerAliasLookup: false }, DeadLineMetadata()) + async GetForwardingHistory(indexOffset: number, startTime = 0, endTime = 0): Promise { + const { response } = await this.lightning.forwardingHistory({ indexOffset, numMaxEvents: 0, startTime: BigInt(startTime), endTime: BigInt(endTime), peerAliasLookup: false }, DeadLineMetadata()) return response } diff --git a/src/services/lnd/settings.ts b/src/services/lnd/settings.ts index 04f31c91..f777e09d 100644 --- a/src/services/lnd/settings.ts +++ b/src/services/lnd/settings.ts @@ -1,3 +1,4 @@ +import { Channel, ChannelEventUpdate } from "../../../proto/lnd/lightning" import { HtlcEvent } from "../../../proto/lnd/router" export type NodeSettings = { lndAddr: string @@ -35,6 +36,7 @@ export type AddressPaidCb = (txOutput: TxOutput, address: string, amount: number export type InvoicePaidCb = (paymentRequest: string, amount: number, used: 'lnd' | 'provider' | 'internal') => Promise export type NewBlockCb = (height: number) => void export type HtlcCb = (event: HtlcEvent) => void +export type ChannelEventCb = (event: ChannelEventUpdate, channels: Channel[]) => void export type NodeInfo = { alias: string diff --git a/src/services/main/adminManager.ts b/src/services/main/adminManager.ts index f56bca2f..039fe419 100644 --- a/src/services/main/adminManager.ts +++ b/src/services/main/adminManager.ts @@ -160,6 +160,7 @@ export class AdminManager { ListChannels = async (): Promise => { const { channels } = await this.lnd.ListChannels(true) const { identityPubkey } = await this.lnd.GetInfo() + const activity = await this.storage.metricsStorage.GetChannelsActivity() const openChannels = await Promise.all(channels.map(async c => { const info = await this.lnd.GetChannelInfo(c.chanId) const policies = [{ pub: info.node1Pub, policy: info.node1Policy }, { pub: info.node2Pub, policy: info.node2Policy }] @@ -182,6 +183,7 @@ export class AdminManager { label: c.peerAlias || c.remotePubkey, lifetime: Number(c.lifetime), policy, + inactive_since_unix: activity[c.chanId] || 0 } })) return { diff --git a/src/services/main/index.ts b/src/services/main/index.ts index 5c839d08..15f0cf7c 100644 --- a/src/services/main/index.ts +++ b/src/services/main/index.ts @@ -6,7 +6,7 @@ import ApplicationManager from './applicationManager.js' import PaymentManager, { PendingTx } from './paymentManager.js' import { MainSettings } from './settings.js' import LND from "../lnd/lnd.js" -import { AddressPaidCb, HtlcCb, InvoicePaidCb, NewBlockCb } from "../lnd/settings.js" +import { AddressPaidCb, ChannelEventCb, HtlcCb, InvoicePaidCb, NewBlockCb } from "../lnd/settings.js" import { ERROR, getLogger, PubLogger } from "../helpers/logger.js" import AppUserManager from "./appUserManager.js" import { Application } from '../storage/entity/Application.js' @@ -68,7 +68,7 @@ export default class { const updateProviderBalance = (b: number) => this.storage.liquidityStorage.IncrementTrackedProviderBalance('lnPub', settings.liquiditySettings.liquidityProviderPub, b) this.liquidityProvider = new LiquidityProvider(settings.liquiditySettings.liquidityProviderPub, this.utils, this.invoicePaidCb, updateProviderBalance) this.rugPullTracker = new RugPullTracker(this.storage, this.liquidityProvider) - this.lnd = new LND(settings.lndSettings, this.liquidityProvider, this.utils, this.addressPaidCb, this.invoicePaidCb, this.newBlockCb, this.htlcCb) + this.lnd = new LND(settings.lndSettings, this.liquidityProvider, this.utils, this.addressPaidCb, this.invoicePaidCb, this.newBlockCb, this.htlcCb, this.channelEventCb) this.liquidityManager = new LiquidityManager(this.settings.liquiditySettings, this.storage, this.utils, this.liquidityProvider, this.lnd, this.rugPullTracker) this.metricsManager = new MetricsManager(this.storage, this.lnd) @@ -137,6 +137,10 @@ export default class { } } + channelEventCb: ChannelEventCb = (e, channels) => { + this.metricsManager.ChannelEventCb(e, channels) + } + htlcCb: HtlcCb = (e) => { this.metricsManager.HtlcCb(e) } diff --git a/src/services/metrics/index.ts b/src/services/metrics/index.ts index 41fb82fb..caa5016f 100644 --- a/src/services/metrics/index.ts +++ b/src/services/metrics/index.ts @@ -3,6 +3,7 @@ import Storage from '../storage/index.js' import * as Types from '../../../proto/autogenerated/ts/types.js' import { Application } from '../storage/entity/Application.js' import { HtlcEvent, HtlcEvent_EventType } from '../../../proto/lnd/router.js' +import { Channel, ChannelEventUpdate, ChannelPoint } from '../../../proto/lnd/lightning.js' import { BalanceInfo } from '../lnd/settings.js' import { BalanceEvent } from '../storage/entity/BalanceEvent.js' import { ChannelBalanceEvent } from '../storage/entity/ChannelsBalanceEvent.js' @@ -13,7 +14,6 @@ import { getLogger } from '../helpers/logger.js' import { encodeTLV, usageMetricsToTlv } from '../helpers/tlv.js' import { ChannelCloseSummary_ClosureType } from '../../../proto/lnd/lightning.js' - export default class Handler { storage: Storage @@ -46,6 +46,29 @@ export default class Handler { } } + async ChannelEventCb(event: ChannelEventUpdate, channels: Channel[]) { + if (event.channel.oneofKind === 'inactiveChannel') { + const channel = this.getRelevantChannel(event.channel.inactiveChannel, channels) + if (!channel) { + return + } + await this.storage.metricsStorage.FlagInactiveChannel(channel.chanId) + return + } else if (event.channel.oneofKind === 'activeChannel') { + const channel = this.getRelevantChannel(event.channel.activeChannel, channels) + if (!channel) { + return + } + await this.storage.metricsStorage.FlagActiveChannel(channel.chanId) + return + } + } + + getRelevantChannel(c: ChannelPoint, channels: Channel[]) { + const point = `${c.fundingTxid}:${c.outputIndex}` + return channels.find(c => c.channelPoint === point) + } + async HtlcCb(htlc: HtlcEvent) { @@ -309,14 +332,30 @@ export default class Handler { } + async GetLndForwardingMetrics(req: Types.LndMetricsRequest): Promise { + const fwEvents = await this.lnd.GetForwardingHistory(0, req.from_unix, req.to_unix) + let totalFees = 0 + const events: Types.LndForwardingEvent[] = fwEvents.forwardingEvents.map(e => { + totalFees += Number(e.fee) + return { + chan_id_in: e.chanIdIn, chan_id_out: e.chanIdOut, amt_in: Number(e.amtIn), amt_out: Number(e.amtOut), fee: Number(e.fee), at_unix: Number(e.timestampNs) + } + }) + return { + total_fees: totalFees, + events: events + } + } + async GetLndMetrics(req: Types.LndMetricsRequest): Promise { - const [chansInfo, pendingChansInfo, closedChansInfo, routing, rootOps] = await Promise.all([ + const [chansInfo, pendingChansInfo, closedChansInfo, routing, rootOps, channelsActivity] = await Promise.all([ this.GetChannelsInfo(), this.GetPendingChannelsInfo(), this.lnd.ListClosedChannels(), this.storage.metricsStorage.GetChannelRouting({ from: req.from_unix, to: req.to_unix }), - this.storage.metricsStorage.GetRootOperations({ from: req.from_unix, to: req.to_unix }) + this.storage.metricsStorage.GetRootOperations({ from: req.from_unix, to: req.to_unix }), + this.storage.metricsStorage.GetChannelsActivity() ]) const { openChannels, totalActive, totalInactive } = chansInfo const { totalPendingOpen, totalPendingClose } = pendingChansInfo @@ -364,7 +403,7 @@ export default class Handler { offline_channels: totalInactive, online_channels: totalActive, closed_channels: closed, - open_channels: openChannels.map(c => ({ channel_point: c.channelPoint, active: c.active, capacity: Number(c.capacity), channel_id: c.chanId, lifetime: Number(c.lifetime), local_balance: Number(c.localBalance), remote_balance: Number(c.remoteBalance), label: c.peerAlias })), + open_channels: openChannels.map(c => ({ channel_point: c.channelPoint, active: c.active, capacity: Number(c.capacity), channel_id: c.chanId, lifetime: Number(c.lifetime), local_balance: Number(c.localBalance), remote_balance: Number(c.remoteBalance), label: c.peerAlias, inactive_since_unix: channelsActivity[c.chanId] || 0 })), forwarding_events: totalEvents, forwarding_fees: totalFees, root_ops: rootOps.map(r => ({ amount: r.operation_amount, created_at_unix: r.at_unix || 0, op_id: r.operation_identifier, op_type: mapRootOpType(r.operation_type) })), diff --git a/src/services/serverMethods/index.ts b/src/services/serverMethods/index.ts index 65d36ddf..5e204369 100644 --- a/src/services/serverMethods/index.ts +++ b/src/services/serverMethods/index.ts @@ -46,6 +46,9 @@ export default (mainHandler: Main): Types.ServerMethods => { GetLndMetrics: async ({ ctx, req }) => { return mainHandler.metricsManager.GetLndMetrics(req) }, + GetLndForwardingMetrics: async ({ ctx, req }) => { + return mainHandler.metricsManager.GetLndForwardingMetrics(req) + }, ResetMetricsStorages: async ({ ctx }) => { return mainHandler.utils.tlvStorageFactory.ResetStorages() }, @@ -85,8 +88,7 @@ export default (mainHandler: Main): Types.ServerMethods => { }, CloseChannel: async ({ ctx, req }) => { const err = Types.CloseChannelRequestValidate(req, { - funding_txid_CustomCheck: chanId => chanId !== '', - sat_per_v_byte_CustomCheck: spv => spv > 0 + funding_txid_CustomCheck: chanId => chanId !== '' }) if (err != null) throw new Error(err.message) return mainHandler.adminManager.CloseChannel(req) @@ -411,4 +413,4 @@ export default (mainHandler: Main): Types.ServerMethods => { return mainHandler.appUserManager.GetHttpCreds(ctx) }, } -} \ No newline at end of file +} diff --git a/src/services/storage/db/db.ts b/src/services/storage/db/db.ts index 197b635d..770476a9 100644 --- a/src/services/storage/db/db.ts +++ b/src/services/storage/db/db.ts @@ -25,6 +25,7 @@ import { DebitAccess } from "../entity/DebitAccess.js" import { RootOperation } from "../entity/RootOperation.js" import { UserOffer } from "../entity/UserOffer.js" import { ManagementGrant } from "../entity/ManagementGrant.js" +import { ChannelEvent } from "../entity/ChannelEvent.js" export type DbSettings = { @@ -76,7 +77,8 @@ export const MetricsDbEntities = { 'BalanceEvent': BalanceEvent, 'ChannelBalanceEvent': ChannelBalanceEvent, 'ChannelRouting': ChannelRouting, - 'RootOperation': RootOperation + 'RootOperation': RootOperation, + 'ChannelEvent': ChannelEvent } export type MetricsDbNames = keyof typeof MetricsDbEntities export const MetricsDbEntitiesNames = Object.keys(MetricsDbEntities) diff --git a/src/services/storage/entity/ChannelEvent.ts b/src/services/storage/entity/ChannelEvent.ts new file mode 100644 index 00000000..bf836170 --- /dev/null +++ b/src/services/storage/entity/ChannelEvent.ts @@ -0,0 +1,22 @@ +import { Entity, PrimaryGeneratedColumn, Column, Index, Check, CreateDateColumn, UpdateDateColumn } from "typeorm" + +@Entity() +export class ChannelEvent { + @PrimaryGeneratedColumn() + serial_id: number + + @Column() + channel_id: string + + @Column() + event_type: 'activity' + + @Column({ default: 0 }) + inactive_since_unix: number + + @CreateDateColumn() + created_at: Date + + @UpdateDateColumn() + updated_at: Date +} diff --git a/src/services/storage/metricsStorage.ts b/src/services/storage/metricsStorage.ts index 8061b1b7..e4cd8e54 100644 --- a/src/services/storage/metricsStorage.ts +++ b/src/services/storage/metricsStorage.ts @@ -8,6 +8,8 @@ import { ChannelRouting } from "./entity/ChannelRouting.js"; import { RootOperation } from "./entity/RootOperation.js"; import { StorageInterface } from "./db/storageInterface.js"; import { Utils } from "../helpers/utilsWrapper.js"; +import { Channel, ChannelEventUpdate } from "../../../proto/lnd/lightning.js"; +import { ChannelEvent } from "./entity/ChannelEvent.js"; export default class { //DB: DataSource | EntityManager settings: StorageSettings @@ -27,6 +29,42 @@ export default class { //return executedMigrations; } + async FlagActiveChannel(chanId: string) { + const existing = await this.dbs.FindOne('ChannelEvent', { where: { channel_id: chanId, event_type: 'activity' } }) + if (!existing) { + await this.dbs.CreateAndSave('ChannelEvent', { channel_id: chanId, event_type: 'activity', inactive_since_unix: 0 }) + return + } + + if (existing.inactive_since_unix > 0) { + await this.dbs.Update('ChannelEvent', existing.serial_id, { inactive_since_unix: 0 }) + return + } + return + } + + async FlagInactiveChannel(chanId: string) { + const existing = await this.dbs.FindOne('ChannelEvent', { where: { channel_id: chanId, event_type: 'activity' } }) + if (!existing) { + await this.dbs.CreateAndSave('ChannelEvent', { channel_id: chanId, event_type: 'activity', inactive_since_unix: Math.floor(Date.now() / 1000) }) + return + } + if (existing.inactive_since_unix > 0) { + return + } + await this.dbs.Update('ChannelEvent', existing.serial_id, { inactive_since_unix: Math.floor(Date.now() / 1000) }) + return + } + + async GetChannelsActivity(): Promise> { + const events = await this.dbs.Find('ChannelEvent', { where: { event_type: 'activity' } }) + const activityMap: Record = {} + events.forEach(e => { + activityMap[e.channel_id] = e.inactive_since_unix + }) + return activityMap + } + async SaveBalanceEvents(balanceEvent: Partial, channelBalanceEvents: Partial[]) { //const blanceEventEntry = this.DB.getRepository(BalanceEvent).create(balanceEvent) //const balanceEntry = await this.txQueue.PushToQueue({ exec: async db => db.getRepository(BalanceEvent).save(blanceEventEntry), dbTx: false }) diff --git a/src/services/storage/migrations/1750777346411-channel_events.ts b/src/services/storage/migrations/1750777346411-channel_events.ts new file mode 100644 index 00000000..69efebe7 --- /dev/null +++ b/src/services/storage/migrations/1750777346411-channel_events.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class ChannelEvents1750777346411 implements MigrationInterface { + name = 'ChannelEvents1750777346411' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "channel_event" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "channel_id" varchar NOT NULL, "event_type" varchar NOT NULL, "inactive_since_unix" integer NOT NULL DEFAULT (0), "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "channel_event"`); + } + +} diff --git a/src/services/storage/migrations/runner.ts b/src/services/storage/migrations/runner.ts index be0eedfe..5217cc98 100644 --- a/src/services/storage/migrations/runner.ts +++ b/src/services/storage/migrations/runner.ts @@ -16,9 +16,10 @@ import { UserCbUrl1727112281043 } from './1727112281043-user_cb_url.js' import { RootOps1732566440447 } from './1732566440447-root_ops.js' import { UserOffer1733502626042 } from './1733502626042-user_offer.js' import { RootOpsTime1745428134124 } from './1745428134124-root_ops_time.js' +import { ChannelEvents1750777346411 } from './1750777346411-channel_events.js' import { ManagementGrant1751307732346 } from './1751307732346-management_grant.js' export const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354, UserCbUrl1727112281043, UserOffer1733502626042, ManagementGrant1751307732346] -export const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825, RootOps1732566440447, RootOpsTime1745428134124] +export const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825, RootOps1732566440447, RootOpsTime1745428134124, ChannelEvents1750777346411] /* export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise => { await connectAndMigrate(log, storageManager, allMigrations, allMetricsMigrations) return false diff --git a/src/tests/networkSetup.ts b/src/tests/networkSetup.ts index b169c7c7..c9720560 100644 --- a/src/tests/networkSetup.ts +++ b/src/tests/networkSetup.ts @@ -14,8 +14,8 @@ export const setupNetwork = async (): Promise => { await core.InitAddress() await core.Mine(1) const setupUtils = new Utils({ dataDir: settings.storageSettings.dataDir, allowResetMetricsStorages: settings.allowResetMetricsStorages }) - const alice = new LND(settings.lndSettings, new LiquidityProvider("", setupUtils, async () => { }, async () => { }), setupUtils, async () => { }, async () => { }, () => { }, () => { }) - const bob = new LND({ ...settings.lndSettings, mainNode: settings.lndSettings.otherNode }, new LiquidityProvider("", setupUtils, async () => { }, async () => { }), setupUtils, async () => { }, async () => { }, () => { }, () => { }) + const alice = new LND(settings.lndSettings, new LiquidityProvider("", setupUtils, async () => { }, async () => { }), setupUtils, async () => { }, async () => { }, () => { }, () => { }, () => { }) + const bob = new LND({ ...settings.lndSettings, mainNode: settings.lndSettings.otherNode }, new LiquidityProvider("", setupUtils, async () => { }, async () => { }), setupUtils, async () => { }, async () => { }, () => { }, () => { }, () => { }) await tryUntil(async i => { const peers = await alice.ListPeers() if (peers.peers.length > 0) { diff --git a/src/tests/testBase.ts b/src/tests/testBase.ts index 939ce5fb..95454a95 100644 --- a/src/tests/testBase.ts +++ b/src/tests/testBase.ts @@ -78,11 +78,11 @@ export const SetupTest = async (d: Describe, chainTools: ChainTools): Promise { }, async () => { }), extermnalUtils, async () => { }, async () => { }, () => { }, () => { }) + const externalAccessToOtherLnd = new LND(otherLndSetting, new LiquidityProvider("", extermnalUtils, async () => { }, async () => { }), extermnalUtils, async () => { }, async () => { }, () => { }, () => { }, () => { }) await externalAccessToOtherLnd.Warmup() const thirdLndSetting = { ...settings.lndSettings, mainNode: settings.lndSettings.thirdNode } - const externalAccessToThirdLnd = new LND(thirdLndSetting, new LiquidityProvider("", extermnalUtils, async () => { }, async () => { }), extermnalUtils, async () => { }, async () => { }, () => { }, () => { }) + const externalAccessToThirdLnd = new LND(thirdLndSetting, new LiquidityProvider("", extermnalUtils, async () => { }, async () => { }), extermnalUtils, async () => { }, async () => { }, () => { }, () => { }, () => { }) await externalAccessToThirdLnd.Warmup()