fix balance data

This commit is contained in:
boufni95 2024-08-28 20:08:02 +02:00
parent fe497d209b
commit 610cdbdc19
13 changed files with 4697 additions and 4648 deletions

View file

@ -4,12 +4,13 @@ import { ChannelBalanceEvent } from "./build/src/services/storage/entity/Channel
import { ChannelRouting } from "./build/src/services/storage/entity/ChannelRouting.js" import { ChannelRouting } from "./build/src/services/storage/entity/ChannelRouting.js"
import { LndMetrics1703170330183 } from './build/src/services/storage/migrations/1703170330183-lnd_metrics.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 { ChannelRouting1709316653538 } from './build/src/services/storage/migrations/1709316653538-channel_routing.js'
import { HtlcCount1724266887195 } from './build/src/services/storage/migrations/1724266887195-htlc_count.js'
export default new DataSource({ export default new DataSource({
type: "sqlite", type: "sqlite",
database: "metrics.sqlite", database: "metrics.sqlite",
entities: [BalanceEvent, ChannelBalanceEvent, ChannelRouting], entities: [BalanceEvent, ChannelBalanceEvent, ChannelRouting],
migrations: [LndMetrics1703170330183, ChannelRouting1709316653538] migrations: [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195]
}); });
//npx typeorm migration:generate ./src/services/storage/migrations/htlc_count -d ./metricsDatasource.js //npx typeorm migration:generate ./src/services/storage/migrations/balance_events -d ./metricsDatasource.js

View file

@ -613,137 +613,54 @@ The nostr server will send back a message response, and inside the body there wi
## Messages ## Messages
### The content of requests and response from the methods ### The content of requests and response from the methods
### AppsMetrics
- __apps__: ARRAY of: _[AppMetrics](#AppMetrics)_
### NewInvoiceRequest
- __amountSats__: _number_
- __memo__: _string_
### NewInvoiceResponse
- __invoice__: _string_
### SetMockAppUserBalanceRequest
- __user_identifier__: _string_
- __amount__: _number_
### PayAddressRequest
- __address__: _string_
- __amoutSats__: _number_
- __satsPerVByte__: _number_
### HttpCreds
- __url__: _string_
- __token__: _string_
### CreateOneTimeInviteLinkResponse
- __invitation_link__: _string_
### UseInviteLinkRequest
- __invite_token__: _string_
### GetInviteTokenStateResponse
- __used__: _boolean_
### ClosedChannel
- __channel_id__: _string_
- __capacity__: _number_
- __closed_height__: _number_
### NewAddressResponse
- __address__: _string_
### DecodeInvoiceRequest
- __invoice__: _string_
### GetUserOperationsResponse ### GetUserOperationsResponse
- __latestIncomingUserToUserPayemnts__: _[UserOperations](#UserOperations)_
- __latestOutgoingInvoiceOperations__: _[UserOperations](#UserOperations)_ - __latestOutgoingInvoiceOperations__: _[UserOperations](#UserOperations)_
- __latestIncomingInvoiceOperations__: _[UserOperations](#UserOperations)_ - __latestIncomingInvoiceOperations__: _[UserOperations](#UserOperations)_
- __latestOutgoingTxOperations__: _[UserOperations](#UserOperations)_ - __latestOutgoingTxOperations__: _[UserOperations](#UserOperations)_
- __latestIncomingTxOperations__: _[UserOperations](#UserOperations)_ - __latestIncomingTxOperations__: _[UserOperations](#UserOperations)_
- __latestOutgoingUserToUserPayemnts__: _[UserOperations](#UserOperations)_ - __latestOutgoingUserToUserPayemnts__: _[UserOperations](#UserOperations)_
- __latestIncomingUserToUserPayemnts__: _[UserOperations](#UserOperations)_
### AddProductRequest ### AuthAppRequest
- __name__: _string_ - __name__: _string_
- __price_sats__: _number_ - __allow_user_creation__: _boolean_ *this field is optional
### SendAppUserToAppUserPaymentRequest
- __from_user_identifier__: _string_
- __to_user_identifier__: _string_
- __amount__: _number_
### PayInvoiceResponse
- __preimage__: _string_
- __amount_paid__: _number_
- __operation_id__: _string_
- __service_fee__: _number_
- __network_fee__: _number_
### OpenChannelResponse
- __channelId__: _string_
### LndChannels
- __open_channels__: ARRAY of: _[OpenChannel](#OpenChannel)_
### BanUserRequest
- __user_id__: _string_
### GetAppUserLNURLInfoRequest ### GetAppUserLNURLInfoRequest
- __user_identifier__: _string_ - __user_identifier__: _string_
- __base_url_override__: _string_ - __base_url_override__: _string_
### DecodeInvoiceResponse
- __amount__: _number_
### GetProductBuyLinkResponse
- __link__: _string_
### MigrationUpdate
- __closure__: _[ClosureMigration](#ClosureMigration)_ *this field is optional
- __relays__: _[RelaysMigration](#RelaysMigration)_ *this field is optional
### UsersInfo
- __always_been_inactive__: _number_
- __balance_avg__: _number_
- __balance_median__: _number_
- __total__: _number_
- __no_balance__: _number_
- __negative_balance__: _number_
### RoutingEvent
- __offchain__: _boolean_
- __outgoing_channel_id__: _number_
- __outgoing_htlc_id__: _number_
- __event_type__: _string_
- __incoming_amt_msat__: _number_
- __failure_string__: _string_
- __forward_fail_event__: _boolean_
- __incoming_channel_id__: _number_
- __incoming_htlc_id__: _number_
- __timestamp_ns__: _number_
- __outgoing_amt_msat__: _number_
- __settled__: _boolean_
### OpenChannel
- __capacity__: _number_
- __active__: _boolean_
- __lifetime__: _number_
- __local_balance__: _number_
- __remote_balance__: _number_
- __label__: _string_
- __channel_id__: _string_
### AddAppUserInvoiceRequest ### AddAppUserInvoiceRequest
- __http_callback_url__: _string_
- __invoice_req__: _[NewInvoiceRequest](#NewInvoiceRequest)_
- __receiver_identifier__: _string_ - __receiver_identifier__: _string_
- __payer_identifier__: _string_ - __payer_identifier__: _string_
- __http_callback_url__: _string_
- __invoice_req__: _[NewInvoiceRequest](#NewInvoiceRequest)_
### PayInvoiceRequest ### NewAddressResponse
- __invoice__: _string_ - __address__: _string_
### Product
- __id__: _string_
- __name__: _string_
- __price_sats__: _number_
### CreateOneTimeInviteLinkResponse
- __invitation_link__: _string_
### AppsMetricsRequest
- __include_operations__: _boolean_ *this field is optional
- __from_unix__: _number_ *this field is optional
- __to_unix__: _number_ *this field is optional
### LndGetInfoRequest
- __nodeId__: _number_
### SetMockAppBalanceRequest
- __amount__: _number_ - __amount__: _number_
### LnurlLinkResponse
- __lnurl__: _string_
- __k1__: _string_
### LnurlWithdrawInfoResponse ### LnurlWithdrawInfoResponse
- __tag__: _string_ - __tag__: _string_
- __callback__: _string_ - __callback__: _string_
@ -754,42 +671,140 @@ The nostr server will send back a message response, and inside the body there wi
- __balanceCheck__: _string_ - __balanceCheck__: _string_
- __payLink__: _string_ - __payLink__: _string_
### HandleLnurlPayResponse ### AddAppUserRequest
- __routes__: ARRAY of: _[Empty](#Empty)_ - __identifier__: _string_
- __pr__: _string_ - __fail_if_exists__: _boolean_
- __balance__: _number_
### AddAppInvoiceRequest
- __payer_identifier__: _string_
- __http_callback_url__: _string_
- __invoice_req__: _[NewInvoiceRequest](#NewInvoiceRequest)_
### AddAppRequest
- __name__: _string_
- __allow_user_creation__: _boolean_
### PayAddressResponse
- __service_fee__: _number_
- __network_fee__: _number_
- __txId__: _string_
- __operation_id__: _string_
### RequestNPubLinkingTokenResponse
- __token__: _string_
### UsageMetric
- __parsed_in_nano__: _number_
- __rpc_name__: _string_
- __batch_size__: _number_
- __processed_at_ms__: _number_
- __auth_in_nano__: _number_
- __validate_in_nano__: _number_
- __handle_in_nano__: _number_
- __batch__: _boolean_
- __nostr__: _boolean_
### SetMockInvoiceAsPaidRequest
- __invoice__: _string_
- __amount__: _number_
### LndGetInfoResponse
- __alias__: _string_
### HttpCreds
- __url__: _string_
- __token__: _string_
### OpenChannel
- __capacity__: _number_
- __active__: _boolean_
- __lifetime__: _number_
- __local_balance__: _number_
- __remote_balance__: _number_
- __label__: _string_
- __channel_id__: _string_
### LndNodeMetrics
- __pending_channels__: _number_
- __closing_channels__: _number_
- __forwarding_events__: _number_
- __forwarding_fees__: _number_
- __chain_balance__: ARRAY of: _[GraphPoint](#GraphPoint)_
- __channel_balance__: ARRAY of: _[GraphPoint](#GraphPoint)_
- __external_balance__: ARRAY of: _[GraphPoint](#GraphPoint)_
- __offline_channels__: _number_
- __online_channels__: _number_
- __open_channels__: ARRAY of: _[OpenChannel](#OpenChannel)_
- __closed_channels__: ARRAY of: _[ClosedChannel](#ClosedChannel)_
### OpenChannelResponse
- __channelId__: _string_
### LinkNPubThroughTokenRequest ### LinkNPubThroughTokenRequest
- __token__: _string_ - __token__: _string_
### LndMetricsRequest
- __from_unix__: _number_ *this field is optional
- __to_unix__: _number_ *this field is optional
### DecodeInvoiceResponse
- __amount__: _number_
### BanUserRequest
- __user_id__: _string_
### AppUser ### AppUser
- __identifier__: _string_ - __identifier__: _string_
- __info__: _[UserInfo](#UserInfo)_ - __info__: _[UserInfo](#UserInfo)_
- __max_withdrawable__: _number_ - __max_withdrawable__: _number_
### NewAddressRequest ### NewInvoiceRequest
- __addressType__: _[AddressType](#AddressType)_ - __amountSats__: _number_
- __memo__: _string_
### GetPaymentStateRequest ### DecodeInvoiceRequest
- __invoice__: _string_ - __invoice__: _string_
### UsersInfo
- __total__: _number_
- __no_balance__: _number_
- __negative_balance__: _number_
- __always_been_inactive__: _number_
- __balance_avg__: _number_
- __balance_median__: _number_
### LndMetrics
- __nodes__: ARRAY of: _[LndNodeMetrics](#LndNodeMetrics)_
### PayAddressRequest
- __address__: _string_
- __amoutSats__: _number_
- __satsPerVByte__: _number_
### PaymentState ### PaymentState
- __paid_at_unix__: _number_ - __paid_at_unix__: _number_
- __amount__: _number_ - __amount__: _number_
- __service_fee__: _number_ - __service_fee__: _number_
- __network_fee__: _number_ - __network_fee__: _number_
### LndMetrics ### UserOperations
- __nodes__: ARRAY of: _[LndNodeMetrics](#LndNodeMetrics)_ - __fromIndex__: _number_
- __toIndex__: _number_
- __operations__: ARRAY of: _[UserOperation](#UserOperation)_
### LndGetInfoResponse ### UsageMetrics
- __alias__: _string_ - __metrics__: ARRAY of: _[UsageMetric](#UsageMetric)_
### AddAppUserRequest ### LndChannels
- __identifier__: _string_ - __open_channels__: ARRAY of: _[OpenChannel](#OpenChannel)_
- __fail_if_exists__: _boolean_
- __balance__: _number_
### SetMockAppBalanceRequest ### RequestNPubLinkingTokenRequest
- __user_identifier__: _string_
### SendAppUserToAppUserPaymentRequest
- __from_user_identifier__: _string_
- __to_user_identifier__: _string_
- __amount__: _number_ - __amount__: _number_
### GetUserOperationsRequest ### GetUserOperationsRequest
@ -801,58 +816,106 @@ The nostr server will send back a message response, and inside the body there wi
- __latestIncomingInvoice__: _number_ - __latestIncomingInvoice__: _number_
- __latestOutgoingInvoice__: _number_ - __latestOutgoingInvoice__: _number_
### Product ### GraphPoint
- __id__: _string_ - __x__: _number_
- __name__: _string_ - __y__: _number_
- __price_sats__: _number_
### RequestNPubLinkingTokenRequest ### GetAppUserRequest
- __user_identifier__: _string_ - __user_identifier__: _string_
### AppMetrics ### OpenChannelRequest
- __app__: _[Application](#Application)_ - __pushAmount__: _number_
- __users__: _[UsersInfo](#UsersInfo)_ - __closeAddress__: _string_
- __available__: _number_ - __destination__: _string_
- __total_fees__: _number_ - __fundingAmount__: _number_
- __received__: _number_
- __spent__: _number_
- __fees__: _number_
- __invoices__: _number_
- __operations__: ARRAY of: _[UserOperation](#UserOperation)_
### AddAppInvoiceRequest ### EnrollAdminTokenRequest
- __invoice_req__: _[NewInvoiceRequest](#NewInvoiceRequest)_ - __admin_token__: _string_
- __payer_identifier__: _string_
- __http_callback_url__: _string_ ### LndSeed
- __seed__: ARRAY of: _string_
### RoutingEvent
- __outgoing_amt_msat__: _number_
- __settled__: _boolean_
- __forward_fail_event__: _boolean_
- __incoming_htlc_id__: _number_
- __outgoing_htlc_id__: _number_
- __event_type__: _string_
- __incoming_amt_msat__: _number_
- __offchain__: _boolean_
- __incoming_channel_id__: _number_
- __outgoing_channel_id__: _number_
- __timestamp_ns__: _number_
- __failure_string__: _string_
### HandleLnurlPayResponse
- __routes__: ARRAY of: _[Empty](#Empty)_
- __pr__: _string_
### GetProductBuyLinkResponse
- __link__: _string_
### GetInviteTokenStateResponse
- __used__: _boolean_
### PayAppUserInvoiceRequest
- __amount__: _number_
- __user_identifier__: _string_
- __invoice__: _string_
### PayInvoiceRequest
- __amount__: _number_
- __invoice__: _string_
### LnurlPayInfoResponse
- __maxSendable__: _number_
- __minSendable__: _number_
- __metadata__: _string_
- __allowsNostr__: _boolean_
- __nostrPubkey__: _string_
- __tag__: _string_
- __callback__: _string_
### UserOperation ### UserOperation
- __identifier__: _string_
- __service_fee__: _number_
- __network_fee__: _number_
- __tx_hash__: _string_
- __paidAtUnix__: _number_
- __type__: _[UserOperationType](#UserOperationType)_
- __inbound__: _boolean_
- __amount__: _number_
- __operationId__: _string_
- __confirmed__: _boolean_ - __confirmed__: _boolean_
- __internal__: _boolean_ - __internal__: _boolean_
- __paidAtUnix__: _number_
- __inbound__: _boolean_
- __operationId__: _string_
- __service_fee__: _number_
- __network_fee__: _number_
- __type__: _[UserOperationType](#UserOperationType)_
- __amount__: _number_
- __identifier__: _string_
- __tx_hash__: _string_
### RequestNPubLinkingTokenResponse ### LiveUserOperation
- __token__: _string_ - __operation__: _[UserOperation](#UserOperation)_
### RelaysMigration
- __relays__: ARRAY of: _string_
### GetInviteTokenStateRequest
- __invite_token__: _string_
### AppsMetrics
- __apps__: ARRAY of: _[AppMetrics](#AppMetrics)_
### BannedAppUser
- __app_name__: _string_
- __app_id__: _string_
- __user_identifier__: _string_
- __nostr_pub__: _string_
### NewAddressRequest
- __addressType__: _[AddressType](#AddressType)_
### CreateOneTimeInviteLinkRequest ### CreateOneTimeInviteLinkRequest
- __sats__: _number_ *this field is optional - __sats__: _number_ *this field is optional
### LndMetricsRequest ### UseInviteLinkRequest
- __from_unix__: _number_ *this field is optional - __invite_token__: _string_
- __to_unix__: _number_ *this field is optional
### BannedAppUser
- __app_id__: _string_
- __user_identifier__: _string_
- __nostr_pub__: _string_
- __app_name__: _string_
### Application ### Application
- __name__: _string_ - __name__: _string_
@ -860,52 +923,48 @@ The nostr server will send back a message response, and inside the body there wi
- __balance__: _number_ - __balance__: _number_
- __npub__: _string_ - __npub__: _string_
### UsageMetric ### SetMockAppUserBalanceRequest
- __processed_at_ms__: _number_ - __user_identifier__: _string_
- __parsed_in_nano__: _number_
- __handle_in_nano__: _number_
- __rpc_name__: _string_
- __batch__: _boolean_
- __auth_in_nano__: _number_
- __validate_in_nano__: _number_
- __nostr__: _boolean_
- __batch_size__: _number_
### SetMockInvoiceAsPaidRequest
- __invoice__: _string_
- __amount__: _number_ - __amount__: _number_
### AuthAppRequest ### NewInvoiceResponse
- __name__: _string_ - __invoice__: _string_
- __allow_user_creation__: _boolean_ *this field is optional
### PayInvoiceResponse
- __operation_id__: _string_
- __service_fee__: _number_
- __network_fee__: _number_
- __preimage__: _string_
- __amount_paid__: _number_
### GetPaymentStateRequest
- __invoice__: _string_
### AppMetrics
- __app__: _[Application](#Application)_
- __users__: _[UsersInfo](#UsersInfo)_
- __invoices__: _number_
- __fees__: _number_
- __total_fees__: _number_
- __operations__: ARRAY of: _[UserOperation](#UserOperation)_
- __received__: _number_
- __spent__: _number_
- __available__: _number_
### AuthApp ### AuthApp
- __app__: _[Application](#Application)_ - __app__: _[Application](#Application)_
- __auth_token__: _string_ - __auth_token__: _string_
### RelaysMigration ### AddProductRequest
- __relays__: ARRAY of: _string_
### UsageMetrics
- __metrics__: ARRAY of: _[UsageMetric](#UsageMetric)_
### GraphPoint
- __y__: _number_
- __x__: _number_
### BanUserResponse
- __balance_sats__: _number_
- __banned_app_users__: ARRAY of: _[BannedAppUser](#BannedAppUser)_
### AddAppRequest
- __name__: _string_ - __name__: _string_
- __allow_user_creation__: _boolean_ - __price_sats__: _number_
### PayAddressResponse ### ClosureMigration
- __operation_id__: _string_ - __closes_at_unix__: _number_
- __service_fee__: _number_
- __network_fee__: _number_ ### SendAppUserToAppPaymentRequest
- __txId__: _string_ - __from_user_identifier__: _string_
- __amount__: _number_
### UserInfo ### UserInfo
- __balance__: _number_ - __balance__: _number_
@ -916,82 +975,24 @@ The nostr server will send back a message response, and inside the body there wi
- __network_max_fee_fixed__: _number_ - __network_max_fee_fixed__: _number_
- __userId__: _string_ - __userId__: _string_
### ClosureMigration ### ClosedChannel
- __closes_at_unix__: _number_ - __channel_id__: _string_
- __capacity__: _number_
- __closed_height__: _number_
### EnrollAdminTokenRequest ### BanUserResponse
- __admin_token__: _string_ - __balance_sats__: _number_
- __banned_app_users__: ARRAY of: _[BannedAppUser](#BannedAppUser)_
### MigrationUpdate
- __closure__: _[ClosureMigration](#ClosureMigration)_ *this field is optional
- __relays__: _[RelaysMigration](#RelaysMigration)_ *this field is optional
### Empty
### EncryptionExchangeRequest ### EncryptionExchangeRequest
- __publicKey__: _string_ - __publicKey__: _string_
- __deviceId__: _string_ - __deviceId__: _string_
### GetInviteTokenStateRequest
- __invite_token__: _string_
### Empty
### LndSeed
- __seed__: ARRAY of: _string_
### SendAppUserToAppPaymentRequest
- __from_user_identifier__: _string_
- __amount__: _number_
### OpenChannelRequest
- __pushAmount__: _number_
- __closeAddress__: _string_
- __destination__: _string_
- __fundingAmount__: _number_
### LnurlPayInfoResponse
- __allowsNostr__: _boolean_
- __nostrPubkey__: _string_
- __tag__: _string_
- __callback__: _string_
- __maxSendable__: _number_
- __minSendable__: _number_
- __metadata__: _string_
### AppsMetricsRequest
- __to_unix__: _number_ *this field is optional
- __include_operations__: _boolean_ *this field is optional
- __from_unix__: _number_ *this field is optional
### LndNodeMetrics
- __pending_channels__: _number_
- __open_channels__: ARRAY of: _[OpenChannel](#OpenChannel)_
- __closed_channels__: ARRAY of: _[ClosedChannel](#ClosedChannel)_
- __forwarding_fees__: _number_
- __channel_balance__: ARRAY of: _[GraphPoint](#GraphPoint)_
- __online_channels__: _number_
- __closing_channels__: _number_
- __forwarding_events__: _number_
- __chain_balance__: ARRAY of: _[GraphPoint](#GraphPoint)_
- __offline_channels__: _number_
### LndGetInfoRequest
- __nodeId__: _number_
### LiveUserOperation
- __operation__: _[UserOperation](#UserOperation)_
### GetAppUserRequest
- __user_identifier__: _string_
### PayAppUserInvoiceRequest
- __user_identifier__: _string_
- __invoice__: _string_
- __amount__: _number_
### LnurlLinkResponse
- __lnurl__: _string_
- __k1__: _string_
### UserOperations
- __fromIndex__: _number_
- __toIndex__: _number_
- __operations__: ARRAY of: _[UserOperation](#UserOperation)_
## Enums ## Enums
### The enumerators used in the messages ### The enumerators used in the messages

File diff suppressed because it is too large Load diff

View file

@ -16,10 +16,10 @@ export type NostrOptions = {
logger?: Logger logger?: Logger
throwErrors?: true throwErrors?: true
metricsCallback: (metrics: Types.RequestMetric[]) => void metricsCallback: (metrics: Types.RequestMetric[]) => void
NostrAdminAuthGuard: (appId?:string, identifier?: string) => Promise<Types.AdminContext>
NostrMetricsAuthGuard: (appId?:string, identifier?: string) => Promise<Types.MetricsContext> NostrMetricsAuthGuard: (appId?:string, identifier?: string) => Promise<Types.MetricsContext>
NostrUserAuthGuard: (appId?:string, identifier?: string) => Promise<Types.UserContext> NostrUserAuthGuard: (appId?:string, identifier?: string) => Promise<Types.UserContext>
NostrGuestWithPubAuthGuard: (appId?:string, identifier?: string) => Promise<Types.GuestWithPubContext> NostrGuestWithPubAuthGuard: (appId?:string, identifier?: string) => Promise<Types.GuestWithPubContext>
NostrAdminAuthGuard: (appId?:string, identifier?: string) => Promise<Types.AdminContext>
} }
const logErrorAndReturnResponse = (error: Error, response: string, res: NostrResponse, logger: Logger, metric: Types.RequestMetric, metricsCallback: (metrics: Types.RequestMetric[]) => void) => { const logErrorAndReturnResponse = (error: Error, response: string, res: NostrResponse, logger: Logger, metric: Types.RequestMetric, metricsCallback: (metrics: Types.RequestMetric[]) => void) => {
logger.error(error.message || error); metricsCallback([{ ...metric, error: response }]); res({ status: 'ERROR', reason: response }) logger.error(error.message || error); metricsCallback([{ ...metric, error: response }]); res({ status: 'ERROR', reason: response })

File diff suppressed because it is too large Load diff

View file

@ -111,6 +111,7 @@ message GraphPoint {
message LndNodeMetrics { message LndNodeMetrics {
repeated GraphPoint chain_balance = 1; repeated GraphPoint chain_balance = 1;
repeated GraphPoint channel_balance = 2; repeated GraphPoint channel_balance = 2;
repeated GraphPoint external_balance = 3;
int64 offline_channels = 4; int64 offline_channels = 4;
int64 online_channels = 5; int64 online_channels = 5;
int64 pending_channels = 6; int64 pending_channels = 6;

View file

@ -109,33 +109,33 @@ export class Watchdog {
checkBalanceUpdate = async (deltaLnd: number, deltaUsers: number) => { checkBalanceUpdate = async (deltaLnd: number, deltaUsers: number) => {
this.utils.stateBundler.AddBalancePoint('deltaExternal', deltaLnd) this.utils.stateBundler.AddBalancePoint('deltaExternal', deltaLnd)
this.utils.stateBundler.AddBalancePoint('deltaUsers', deltaUsers) this.utils.stateBundler.AddBalancePoint('deltaUsers', deltaUsers)
const lndWithDeltaUsers = this.initialLndBalance + deltaUsers
const result = this.checkDeltas(deltaLnd, deltaUsers) const result = this.checkDeltas(deltaLnd, deltaUsers)
switch (result.type) { switch (result.type) {
case 'mismatch': case 'mismatch':
if (deltaLnd < 0) { if (deltaLnd < 0) {
if (result.absoluteDiff > this.settings.maxDiffSats) { if (result.absoluteDiff > this.settings.maxDiffSats) {
await this.updateDisruption(true, result.absoluteDiff) await this.updateDisruption(true, result.absoluteDiff, lndWithDeltaUsers)
return true return true
} }
} else { } else {
this.log("WARNING! LND balance increased more than users balance with a difference of", result.absoluteDiff, "sats") this.log("WARNING! LND balance increased more than users balance with a difference of", result.absoluteDiff, "sats")
this.updateDisruption(false, result.absoluteDiff) this.updateDisruption(false, result.absoluteDiff, lndWithDeltaUsers)
return false return false
} }
break break
case 'negative': case 'negative':
if (Math.abs(deltaLnd) > Math.abs(deltaUsers)) { if (Math.abs(deltaLnd) > Math.abs(deltaUsers)) {
if (result.absoluteDiff > this.settings.maxDiffSats) { if (result.absoluteDiff > this.settings.maxDiffSats) {
await this.updateDisruption(true, result.absoluteDiff) await this.updateDisruption(true, result.absoluteDiff, lndWithDeltaUsers)
return true return true
} }
} else if (deltaLnd === deltaUsers) { } else if (deltaLnd === deltaUsers) {
await this.updateDisruption(false, 0) await this.updateDisruption(false, 0, lndWithDeltaUsers)
return false return false
} else { } else {
this.log("WARNING! LND balance decreased less than users balance with a difference of", result.absoluteDiff, "sats") this.log("WARNING! LND balance decreased less than users balance with a difference of", result.absoluteDiff, "sats")
await this.updateDisruption(false, result.absoluteDiff) await this.updateDisruption(false, result.absoluteDiff, lndWithDeltaUsers)
return false return false
} }
break break
@ -143,22 +143,23 @@ export class Watchdog {
if (deltaLnd < deltaUsers) { if (deltaLnd < deltaUsers) {
this.log("WARNING! LND balance increased less than users balance with a difference of", result.absoluteDiff, "sats") this.log("WARNING! LND balance increased less than users balance with a difference of", result.absoluteDiff, "sats")
if (result.absoluteDiff > this.settings.maxDiffSats) { if (result.absoluteDiff > this.settings.maxDiffSats) {
await this.updateDisruption(true, result.absoluteDiff) await this.updateDisruption(true, result.absoluteDiff, lndWithDeltaUsers)
return true return true
} }
} else if (deltaLnd === deltaUsers) { } else if (deltaLnd === deltaUsers) {
await this.updateDisruption(false, 0) await this.updateDisruption(false, 0, lndWithDeltaUsers)
return false return false
} else { } else {
await this.updateDisruption(false, result.absoluteDiff) await this.updateDisruption(false, result.absoluteDiff, lndWithDeltaUsers)
return false return false
} }
} }
return false return false
} }
updateDisruption = async (isDisrupted: boolean, absoluteDiff: number) => { updateDisruption = async (isDisrupted: boolean, absoluteDiff: number, lndWithDeltaUsers: number) => {
const tracker = await this.getTracker() const tracker = await this.getTracker()
this.storage.liquidityStorage.UpdateTrackedProviderBalance('lnd', this.lndPubKey, lndWithDeltaUsers)
if (isDisrupted) { if (isDisrupted) {
if (tracker.latest_distruption_at_unix === 0) { if (tracker.latest_distruption_at_unix === 0) {
await this.storage.liquidityStorage.UpdateTrackedProviderDisruption('lnd', this.lndPubKey, Math.floor(Date.now() / 1000)) await this.storage.liquidityStorage.UpdateTrackedProviderDisruption('lnd', this.lndPubKey, Math.floor(Date.now() / 1000))

View file

@ -24,11 +24,23 @@ export default class Handler {
} }
async NewBlockCb(height: number, balanceInfo: BalanceInfo) { async NewBlockCb(height: number, balanceInfo: BalanceInfo) {
const providers = await this.storage.liquidityStorage.GetTrackedProviders()
let lndTotal = 0
let providerTotal = 0
providers.forEach(p => {
if (p.provider_type === 'lnd') {
lndTotal += p.latest_balance
} else {
providerTotal += p.latest_balance
}
})
const balanceEvent: Partial<BalanceEvent> = { const balanceEvent: Partial<BalanceEvent> = {
block_height: height, block_height: height,
confirmed_chain_balance: balanceInfo.confirmedBalance, confirmed_chain_balance: balanceInfo.confirmedBalance,
unconfirmed_chain_balance: balanceInfo.unconfirmedBalance, unconfirmed_chain_balance: balanceInfo.unconfirmedBalance,
total_chain_balance: balanceInfo.totalBalance, total_chain_balance: balanceInfo.totalBalance,
channels_balance: lndTotal,
external_balance: providerTotal
} }
const channelsEvents: Partial<ChannelBalanceEvent>[] = balanceInfo.channelsBalance.map(c => ({ const channelsEvents: Partial<ChannelBalanceEvent>[] = balanceInfo.channelsBalance.map(c => ({
channel_id: c.channelId, channel_id: c.channelId,
@ -214,39 +226,21 @@ export default class Handler {
totalEvents += r.events_as_input totalEvents += r.events_as_input
totalFees += r.forward_fee_as_input totalFees += r.forward_fee_as_input
}) })
const { channelsBalanceEvents, chainBalanceEvents } = await this.storage.metricsStorage.GetBalanceEvents({ from: req.from_unix, to: req.to_unix }) const { chainBalanceEvents } = await this.storage.metricsStorage.GetBalanceEvents({ from: req.from_unix, to: req.to_unix })
const chainBalance: Types.GraphPoint[] = [] const chainBalance: Types.GraphPoint[] = []
chainBalanceEvents.forEach(e => {
if (chainBalance.length === 0) {
chainBalance.push({ x: e.block_height, y: e.total_chain_balance })
return
}
const last = chainBalance[chainBalance.length - 1]
if (last.y !== e.total_chain_balance) {
chainBalance.push({ x: e.block_height, y: e.total_chain_balance })
}
})
const chansPerBlock = new Map()
channelsBalanceEvents.forEach(e => {
const height = e.balance_event.block_height
const local = e.local_balance_sats
const v = chansPerBlock.get(height)
if (!v) {
chansPerBlock.set(height, local)
return
}
chansPerBlock.set(height, local + v)
})
const chansBalance: Types.GraphPoint[] = [] const chansBalance: Types.GraphPoint[] = []
chansPerBlock.forEach((v, k) => { const externalBalance: Types.GraphPoint[] = []
if (chansBalance.length === 0) { chainBalanceEvents.forEach(e => {
chansBalance.push({ x: k, y: v }) if (chainBalance.length === 0 || chainBalance[chainBalance.length - 1].y !== e.total_chain_balance) {
return chainBalance.push({ x: e.block_height, y: e.total_chain_balance })
} }
const last = chansBalance[chansBalance.length - 1]
if (last.y !== v) { if (chansBalance.length === 0 || chansBalance[chansBalance.length - 1].y !== e.channels_balance) {
chansBalance.push({ x: k, y: v }) chansBalance.push({ x: e.block_height, y: e.channels_balance })
}
if (externalBalance.length === 0 || externalBalance[externalBalance.length - 1].y !== e.external_balance) {
externalBalance.push({ x: e.block_height, y: e.external_balance })
} }
}) })
@ -254,6 +248,7 @@ export default class Handler {
nodes: [{ nodes: [{
chain_balance: chainBalance, chain_balance: chainBalance,
channel_balance: chansBalance, channel_balance: chansBalance,
external_balance: externalBalance,
closing_channels: totalPendingClose, closing_channels: totalPendingClose,
pending_channels: totalPendingOpen, pending_channels: totalPendingOpen,
offline_channels: totalInactive, offline_channels: totalInactive,

View file

@ -17,6 +17,12 @@ export class BalanceEvent {
@Column() @Column()
total_chain_balance: number total_chain_balance: number
@Column({ default: 0 })
channels_balance: number
@Column({ default: 0 })
external_balance: number
@CreateDateColumn() @CreateDateColumn()
created_at: Date created_at: Date

View file

@ -21,7 +21,7 @@ export class LiquidityStorage {
} }
async GetNoodeSeed(pubkey: string) { async GetNoodeSeed(pubkey: string) {
return this.DB.getRepository(LndNodeInfo).findOne({ where: { pubkey, seed:Not(IsNull()) } }) return this.DB.getRepository(LndNodeInfo).findOne({ where: { pubkey, seed: Not(IsNull()) } })
} }
async SaveNodeSeed(pubkey: string, seed: string) { async SaveNodeSeed(pubkey: string, seed: string) {
@ -43,6 +43,10 @@ export class LiquidityStorage {
await this.txQueue.PushToQueue<LndNodeInfo>({ exec: async db => db.getRepository(LndNodeInfo).save(entry), dbTx: false }) await this.txQueue.PushToQueue<LndNodeInfo>({ exec: async db => db.getRepository(LndNodeInfo).save(entry), dbTx: false })
} }
async GetTrackedProviders() {
return this.DB.getRepository(TrackedProvider).find()
}
async GetTrackedProvider(providerType: 'lnd' | 'lnPub', pub: string) { async GetTrackedProvider(providerType: 'lnd' | 'lnPub', pub: string) {
return this.DB.getRepository(TrackedProvider).findOne({ where: { provider_pubkey: pub, provider_type: providerType } }) return this.DB.getRepository(TrackedProvider).findOne({ where: { provider_pubkey: pub, provider_type: providerType } })
} }

View file

@ -32,11 +32,10 @@ export default class {
async GetBalanceEvents({ from, to }: { from?: number, to?: number }, entityManager = this.DB) { async GetBalanceEvents({ from, to }: { from?: number, to?: number }, entityManager = this.DB) {
const q = getTimeQuery({ from, to }) const q = getTimeQuery({ from, to })
const [chainBalanceEvents, channelsBalanceEvents] = await Promise.all([ const [chainBalanceEvents] = await Promise.all([
entityManager.getRepository(BalanceEvent).find(q), entityManager.getRepository(BalanceEvent).find(q),
entityManager.getRepository(ChannelBalanceEvent).find(q),
]) ])
return { chainBalanceEvents, channelsBalanceEvents } return { chainBalanceEvents }
} }
async initChannelRoutingEvent(dayUnix: number, channelId: string) { async initChannelRoutingEvent(dayUnix: number, channelId: string) {

View file

@ -0,0 +1,20 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class BalanceEvents1724860966825 implements MigrationInterface {
name = 'BalanceEvents1724860966825'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "temporary_balance_event" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "block_height" integer NOT NULL, "confirmed_chain_balance" integer NOT NULL, "unconfirmed_chain_balance" integer NOT NULL, "total_chain_balance" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')), "channels_balance" integer NOT NULL DEFAULT (0), "external_balance" integer NOT NULL DEFAULT (0))`);
await queryRunner.query(`INSERT INTO "temporary_balance_event"("serial_id", "block_height", "confirmed_chain_balance", "unconfirmed_chain_balance", "total_chain_balance", "created_at", "updated_at") SELECT "serial_id", "block_height", "confirmed_chain_balance", "unconfirmed_chain_balance", "total_chain_balance", "created_at", "updated_at" FROM "balance_event"`);
await queryRunner.query(`DROP TABLE "balance_event"`);
await queryRunner.query(`ALTER TABLE "temporary_balance_event" RENAME TO "balance_event"`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "balance_event" RENAME TO "temporary_balance_event"`);
await queryRunner.query(`CREATE TABLE "balance_event" ("serial_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "block_height" integer NOT NULL, "confirmed_chain_balance" integer NOT NULL, "unconfirmed_chain_balance" integer NOT NULL, "total_chain_balance" integer NOT NULL, "created_at" datetime NOT NULL DEFAULT (datetime('now')), "updated_at" datetime NOT NULL DEFAULT (datetime('now')))`);
await queryRunner.query(`INSERT INTO "balance_event"("serial_id", "block_height", "confirmed_chain_balance", "unconfirmed_chain_balance", "total_chain_balance", "created_at", "updated_at") SELECT "serial_id", "block_height", "confirmed_chain_balance", "unconfirmed_chain_balance", "total_chain_balance", "created_at", "updated_at" FROM "temporary_balance_event"`);
await queryRunner.query(`DROP TABLE "temporary_balance_event"`);
}
}

View file

@ -11,8 +11,9 @@ import { TrackedProvider1720814323679 } from './1720814323679-tracked_provider.j
import { CreateInviteTokenTable1721751414878 } from "./1721751414878-create_invite_token_table.js" import { CreateInviteTokenTable1721751414878 } from "./1721751414878-create_invite_token_table.js"
import { PaymentIndex1721760297610 } from './1721760297610-payment_index.js' import { PaymentIndex1721760297610 } from './1721760297610-payment_index.js'
import { HtlcCount1724266887195 } from './1724266887195-htlc_count.js' import { HtlcCount1724266887195 } from './1724266887195-htlc_count.js'
import { BalanceEvents1724860966825 } from './1724860966825-balance_events.js'
const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610] const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610]
const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195] const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825]
export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise<boolean> => { export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise<boolean> => {
if (arg === 'fake_initial_migration') { if (arg === 'fake_initial_migration') {
runFakeMigration(settings.databaseFile, [Initial1703170309875]) runFakeMigration(settings.databaseFile, [Initial1703170309875])