commit
2f3c19473c
21 changed files with 1417 additions and 48 deletions
55
.github/workflows/test.yaml
vendored
Normal file
55
.github/workflows/test.yaml
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
name: Docker Compose Actions Workflow
|
||||
on: push
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: unzip the file
|
||||
run: unzip src/tests/regtestNetwork.zip
|
||||
- name: list files
|
||||
run: ls -la
|
||||
- name: Build the stack
|
||||
run: docker-compose --project-directory ./ -f src/tests/docker-compose.yml up -d
|
||||
- name: Copy alice cert file
|
||||
run: docker cp polar-n2-alice:/home/lnd/.lnd/tls.cert alice-tls.cert
|
||||
- name: Copy bob cert file
|
||||
run: docker cp polar-n2-bob:/home/lnd/.lnd/tls.cert bob-tls.cert
|
||||
- name: Copy carol cert file
|
||||
run: docker cp polar-n2-carol:/home/lnd/.lnd/tls.cert carol-tls.cert
|
||||
- name: Copy dave cert file
|
||||
run: docker cp polar-n2-dave:/home/lnd/.lnd/tls.cert dave-tls.cert
|
||||
- name: Copy alice macaroon file
|
||||
run: docker cp polar-n2-alice:/home/lnd/.lnd/data/chain/bitcoin/regtest/admin.macaroon alice-admin.macaroon
|
||||
- name: Copy bob macaroon file
|
||||
run: docker cp polar-n2-bob:/home/lnd/.lnd/data/chain/bitcoin/regtest/admin.macaroon bob-admin.macaroon
|
||||
- name: Copy carol macaroon file
|
||||
run: docker cp polar-n2-carol:/home/lnd/.lnd/data/chain/bitcoin/regtest/admin.macaroon carol-admin.macaroon
|
||||
- name: Copy dave macaroon file
|
||||
run: docker cp polar-n2-dave:/home/lnd/.lnd/data/chain/bitcoin/regtest/admin.macaroon dave-admin.macaroon
|
||||
- name: copy env file
|
||||
run: cp src/tests/.env.test .env
|
||||
- name: List files
|
||||
run: ls -la
|
||||
- name: Cache node modules
|
||||
id: cache-npm
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
|
||||
name: List the state of node modules
|
||||
continue-on-error: true
|
||||
run: npm list
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
994
package-lock.json
generated
994
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -35,6 +35,7 @@
|
|||
"@types/secp256k1": "^4.0.3",
|
||||
"axios": "^0.28.0",
|
||||
"bech32": "^2.0.0",
|
||||
"bitcoin-core": "^4.2.0",
|
||||
"chai": "^4.3.7",
|
||||
"chai-string": "^1.5.0",
|
||||
"copyfiles": "^2.4.1",
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export interface LightningHandler {
|
|||
PayInvoice(invoice: string, amount: number, feeLimit: number): Promise<PaidInvoice>
|
||||
EstimateChainFees(address: string, amount: number, targetConf: number): Promise<EstimateFeeResponse>
|
||||
PayAddress(address: string, amount: number, satPerVByte: number, label?: string): Promise<SendCoinsResponse>
|
||||
OpenChannel(destination: string, closeAddress: string, fundingAmount: number, pushSats: number): Promise<string>
|
||||
//OpenChannel(destination: string, closeAddress: string, fundingAmount: number, pushSats: number): Promise<string>
|
||||
SetMockInvoiceAsPaid(invoice: string, amount: number): Promise<void>
|
||||
ChannelBalance(): Promise<{ local: number, remote: number }>
|
||||
GetTransactions(startHeight: number): Promise<TransactionDetails>
|
||||
|
|
|
|||
|
|
@ -80,7 +80,22 @@ export default class {
|
|||
this.SubscribeInvoicePaid()
|
||||
this.SubscribeNewBlock()
|
||||
this.SubscribeHtlcEvents()
|
||||
const now = Date.now()
|
||||
return new Promise<void>((res, rej) => {
|
||||
const interval = setInterval(async () => {
|
||||
try {
|
||||
await this.GetInfo()
|
||||
clearInterval(interval)
|
||||
this.ready = true
|
||||
res()
|
||||
} catch (err) {
|
||||
this.log("LND is not ready yet, will try again in 1 second")
|
||||
if (Date.now() - now > 1000 * 60) {
|
||||
rej(new Error("LND not ready after 1 minute"))
|
||||
}
|
||||
}
|
||||
}, 1000)
|
||||
})
|
||||
}
|
||||
|
||||
async GetInfo(): Promise<NodeInfo> {
|
||||
|
|
@ -277,6 +292,7 @@ export default class {
|
|||
stream.responses.onMessage(payment => {
|
||||
switch (payment.status) {
|
||||
case Payment_PaymentStatus.FAILED:
|
||||
console.log(payment)
|
||||
this.log("invoice payment failed", payment.failureReason)
|
||||
rej(PaymentFailureReason[payment.failureReason])
|
||||
return
|
||||
|
|
@ -356,29 +372,37 @@ export default class {
|
|||
return res.response
|
||||
}
|
||||
|
||||
async OpenChannel(destination: string, closeAddress: string, fundingAmount: number, pushSats: number): Promise<string> {
|
||||
await this.Health()
|
||||
async ConnectPeer(addr: { pubkey: string, host: string }) {
|
||||
const res = await this.lightning.connectPeer({
|
||||
addr,
|
||||
perm: true,
|
||||
timeout: 0n
|
||||
}, DeadLineMetadata())
|
||||
return res.response
|
||||
}
|
||||
|
||||
async ListPeers() {
|
||||
const res = await this.lightning.listPeers({ latestError: true }, DeadLineMetadata())
|
||||
return res.response
|
||||
}
|
||||
|
||||
async OpenChannel(destination: string, closeAddress: string, fundingAmount: number, pushSats: number) {
|
||||
const abortController = new AbortController()
|
||||
const req = OpenChannelReq(destination, closeAddress, fundingAmount, pushSats)
|
||||
const stream = this.lightning.openChannel(req, { abort: abortController.signal })
|
||||
return new Promise((res, rej) => {
|
||||
stream.responses.onMessage(message => {
|
||||
|
||||
console.log("message", message)
|
||||
switch (message.update.oneofKind) {
|
||||
case 'chanPending':
|
||||
abortController.abort()
|
||||
res(Buffer.from(message.pendingChanId).toString('base64'))
|
||||
break
|
||||
default:
|
||||
abortController.abort()
|
||||
rej("unexpected state response: " + message.update.oneofKind)
|
||||
}
|
||||
})
|
||||
stream.responses.onError(error => {
|
||||
console.log("error", error)
|
||||
rej(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export default class {
|
|||
async GetForwardingHistory(indexOffset: number): Promise<{ fee: number, chanIdIn: string, chanIdOut: string, timestampNs: number, offset: number }[]> { throw new Error("GetForwardingHistory disabled in mock mode") }
|
||||
|
||||
async GetInfo(): Promise<NodeInfo> {
|
||||
return { alias: "mock", syncedToChain: true, syncedToGraph: true, blockHeight: 1, blockHash: "" }
|
||||
return { alias: "mock", syncedToChain: true, syncedToGraph: true, blockHeight: 1, blockHash: "", identityPubkey: "mock", uris: [] }
|
||||
}
|
||||
|
||||
async Health(): Promise<void> { }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { OpenChannelRequest } from "../../../proto/lnd/lightning";
|
||||
import { CommitmentType, OpenChannelRequest } from "../../../proto/lnd/lightning.js";
|
||||
|
||||
export const OpenChannelReq = (destination: string, closeAddress: string, fundingAmount: number, pushSats: number): OpenChannelRequest => ({
|
||||
nodePubkey: Buffer.from(destination, 'hex'),
|
||||
|
|
@ -9,22 +9,22 @@ export const OpenChannelReq = (destination: string, closeAddress: string, fundin
|
|||
satPerVbyte: 0n, // TBD
|
||||
private: false,
|
||||
minConfs: 0, // TBD
|
||||
baseFee: 0n, // TBD
|
||||
feeRate: 0n, // TBD
|
||||
baseFee: 1n, // TBD
|
||||
feeRate: 1n, // TBD
|
||||
targetConf: 0,
|
||||
zeroConf: false,
|
||||
maxLocalCsv: 0,
|
||||
remoteCsvDelay: 0,
|
||||
spendUnconfirmed: false,
|
||||
minHtlcMsat: 0n,
|
||||
remoteChanReserveSat: 0n,
|
||||
remoteMaxHtlcs: 0,
|
||||
remoteMaxValueInFlightMsat: 0n,
|
||||
useBaseFee: false,
|
||||
useFeeRate: false,
|
||||
minHtlcMsat: 1n,
|
||||
remoteChanReserveSat: 10000n,
|
||||
remoteMaxHtlcs: 483,
|
||||
remoteMaxValueInFlightMsat: 990000000n,
|
||||
useBaseFee: true,
|
||||
useFeeRate: true,
|
||||
|
||||
// Default stuff
|
||||
commitmentType: 0,
|
||||
commitmentType: CommitmentType.ANCHORS,
|
||||
scidAlias: false,
|
||||
nodePubkeyString: "",
|
||||
satPerByte: 0n,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ export type NodeInfo = {
|
|||
syncedToGraph: boolean
|
||||
blockHeight: number
|
||||
blockHash: string
|
||||
identityPubkey: string
|
||||
uris: string[]
|
||||
}
|
||||
export type Invoice = {
|
||||
payRequest: string
|
||||
|
|
|
|||
|
|
@ -19,11 +19,12 @@ export default class {
|
|||
settings: MainSettings
|
||||
paymentManager: PaymentManager
|
||||
nPubLinkingTokens = new Map<string, NsecLinkingData>();
|
||||
linkingTokenInterval: NodeJS.Timeout
|
||||
constructor(storage: Storage, settings: MainSettings, paymentManager: PaymentManager) {
|
||||
this.storage = storage
|
||||
this.settings = settings
|
||||
this.paymentManager = paymentManager
|
||||
setInterval(() => {
|
||||
this.linkingTokenInterval = setInterval(() => {
|
||||
const now = Date.now();
|
||||
for (let [token, data] of this.nPubLinkingTokens) {
|
||||
if (data.expiry <= now) {
|
||||
|
|
@ -35,6 +36,9 @@ export default class {
|
|||
}
|
||||
}, 60 * 1000); // 1 minute
|
||||
}
|
||||
Stop() {
|
||||
clearInterval(this.linkingTokenInterval)
|
||||
}
|
||||
SignAppToken(appId: string): string {
|
||||
return jwt.sign({ appId }, this.settings.jwtSecret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,11 @@ export default class {
|
|||
this.appUserManager = new AppUserManager(this.storage, this.settings, this.applicationManager)
|
||||
|
||||
}
|
||||
Stop() {
|
||||
this.lnd.Stop()
|
||||
this.applicationManager.Stop()
|
||||
this.paymentManager.Stop()
|
||||
}
|
||||
|
||||
attachNostrSend(f: NostrSend) {
|
||||
this.nostrSend = f
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ const defaultLnurlPayMetadata = `[["text/plain", "lnurl pay to Lightning.pub"]]`
|
|||
const confInOne = 1000 * 1000
|
||||
const confInTwo = 100 * 1000 * 1000
|
||||
export default class {
|
||||
|
||||
storage: Storage
|
||||
settings: MainSettings
|
||||
lnd: LightningHandler
|
||||
|
|
@ -54,6 +55,9 @@ export default class {
|
|||
this.addressPaidCb = addressPaidCb
|
||||
this.invoicePaidCb = invoicePaidCb
|
||||
}
|
||||
Stop() {
|
||||
this.watchDog.Stop()
|
||||
}
|
||||
|
||||
getServiceFee(action: Types.UserOperationType, amount: number, appUser: boolean): number {
|
||||
switch (action) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ export type MainSettings = {
|
|||
skipSanityCheck: boolean
|
||||
disableExternalPayments: boolean
|
||||
}
|
||||
export type BitcoinCoreSettings = {
|
||||
port: number
|
||||
user: string
|
||||
pass: string
|
||||
}
|
||||
export type TestSettings = MainSettings & { lndSettings: { otherNode: NodeSettings, thirdNode: NodeSettings, fourthNode: NodeSettings }, bitcoinCoreSettings: BitcoinCoreSettings }
|
||||
export const LoadMainSettingsFromEnv = (): MainSettings => {
|
||||
return {
|
||||
watchDogSettings: LoadWatchdogSettingsFromEnv(),
|
||||
|
|
@ -44,7 +50,7 @@ export const LoadMainSettingsFromEnv = (): MainSettings => {
|
|||
}
|
||||
}
|
||||
|
||||
export const LoadTestSettingsFromEnv = (): MainSettings & { lndSettings: { otherNode: NodeSettings, thirdNode: NodeSettings } } => {
|
||||
export const LoadTestSettingsFromEnv = (): TestSettings => {
|
||||
const eventLogPath = `logs/eventLogV2Test${Date.now()}.csv`
|
||||
const settings = LoadMainSettingsFromEnv()
|
||||
return {
|
||||
|
|
@ -61,8 +67,18 @@ export const LoadTestSettingsFromEnv = (): MainSettings & { lndSettings: { other
|
|||
lndAddr: EnvMustBeNonEmptyString("LND_THIRD_ADDR"),
|
||||
lndCertPath: EnvMustBeNonEmptyString("LND_THIRD_CERT_PATH"),
|
||||
lndMacaroonPath: EnvMustBeNonEmptyString("LND_THIRD_MACAROON_PATH")
|
||||
},
|
||||
fourthNode: {
|
||||
lndAddr: EnvMustBeNonEmptyString("LND_FOURTH_ADDR"),
|
||||
lndCertPath: EnvMustBeNonEmptyString("LND_FOURTH_CERT_PATH"),
|
||||
lndMacaroonPath: EnvMustBeNonEmptyString("LND_FOURTH_MACAROON_PATH")
|
||||
}
|
||||
},
|
||||
skipSanityCheck: true
|
||||
skipSanityCheck: true,
|
||||
bitcoinCoreSettings: {
|
||||
port: EnvMustBeInteger("BITCOIN_CORE_PORT"),
|
||||
user: EnvMustBeNonEmptyString("BITCOIN_CORE_USER"),
|
||||
pass: EnvMustBeNonEmptyString("BITCOIN_CORE_PASS")
|
||||
}
|
||||
}
|
||||
}
|
||||
40
src/tests/.env.test
Normal file
40
src/tests/.env.test
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
LND_ADDRESS=127.0.0.1:10001 #alice
|
||||
LND_CERT_PATH=alice-tls.cert #alice
|
||||
LND_MACAROON_PATH=alice-admin.macaroon
|
||||
DATABASE_FILE=db.sqlite
|
||||
JWT_SECRET=bigsecrethere
|
||||
ALLOW_BALANCE_MIGRATION=true
|
||||
OUTBOUND_MAX_FEE_BPS=60
|
||||
OUTBOUND_MAX_FEE_EXTRA_SATS=100
|
||||
INCOMING_CHAIN_FEE_ROOT_BPS=0
|
||||
OUTGOING_CHAIN_FEE_ROOT_BPS=60 #this is applied only to withdrawls from application wallets
|
||||
INCOMING_INVOICE_FEE_ROOT_BPS=0
|
||||
OUTGOING_INVOICE_FEE_ROOT_BPS=60 #this is applied only to withdrawals from application wallets
|
||||
INCOMING_INVOICE_FEE_USER_BPS=0 #defined by app this is just default
|
||||
OUTGOING_INVOICE_FEE_USER_BPS=60 #defined by app this is just default
|
||||
TX_FEE_INTERNAL_ROOT_BPS=60 #this is applied only to withdrawls from application wallets
|
||||
TX_FEE_INTERNAL_USER_BPS=60 #defined by app this is just default
|
||||
NOSTR_RELAYS=wss://strfry.shock.network
|
||||
SERVICE_URL=http://localhost:8080
|
||||
ADMIN_TOKEN=thisisadmin
|
||||
PORT=8080
|
||||
METRICS_DATABASE_FILE=metrics.sqlite
|
||||
WATCHDOG_MAX_DIFF_BPS=100
|
||||
WATCHDOG_MAX_DIFF_SATS=10000
|
||||
|
||||
# dave <--> alice <--> carol <--> bob
|
||||
LND_OTHER_ADDR=127.0.0.1:10002
|
||||
LND_OTHER_CERT_PATH=bob-tls.cert
|
||||
LND_OTHER_MACAROON_PATH=bob-admin.macaroon
|
||||
|
||||
LND_THIRD_ADDR=127.0.0.1:10003
|
||||
LND_THIRD_CERT_PATH=carol-tls.cert
|
||||
LND_THIRD_MACAROON_PATH=carol-admin.macaroon
|
||||
|
||||
LND_FOURTH_ADDR=127.0.0.1:10004
|
||||
LND_FOURTH_CERT_PATH=dave-tls.cert
|
||||
LND_FOURTH_MACAROON_PATH=dave-admin.macaroon
|
||||
|
||||
BITCOIN_CORE_PORT=18443
|
||||
BITCOIN_CORE_USER=polaruser
|
||||
BITCOIN_CORE_PASS=polarpass
|
||||
17
src/tests/DockerFile
Normal file
17
src/tests/DockerFile
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
FROM node:10-alpine
|
||||
|
||||
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
|
||||
|
||||
WORKDIR /home/node/app
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
USER node
|
||||
|
||||
RUN npm install
|
||||
|
||||
COPY env.example .env
|
||||
|
||||
COPY --chown=node:node . .
|
||||
|
||||
CMD [ "npm", "test" ]
|
||||
39
src/tests/bitcoinCore.ts
Normal file
39
src/tests/bitcoinCore.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// @ts-ignore
|
||||
import BitcoinCore from 'bitcoin-core';
|
||||
import { TestSettings } from '../services/main/settings';
|
||||
export class BitcoinCoreWrapper {
|
||||
core: BitcoinCore
|
||||
addr: { address: string }
|
||||
constructor(settings: TestSettings) {
|
||||
this.core = new BitcoinCore({
|
||||
//network: 'regtest',
|
||||
host: '127.0.0.1',
|
||||
port: `${settings.bitcoinCoreSettings.port}`,
|
||||
username: settings.bitcoinCoreSettings.user,
|
||||
password: settings.bitcoinCoreSettings.pass,
|
||||
// use a long timeout due to the time it takes to mine a lot of blocks
|
||||
timeout: 5 * 60 * 1000,
|
||||
})
|
||||
}
|
||||
InitAddress = async () => {
|
||||
this.addr = await this.core.getNewAddress()
|
||||
}
|
||||
Init = async () => {
|
||||
const wallet = await this.core.createWallet('');
|
||||
console.log({ wallet })
|
||||
await this.InitAddress()
|
||||
console.log({ addr: this.addr })
|
||||
await this.Mine(101)
|
||||
const info = await this.core.getWalletInfo();
|
||||
console.log({ info })
|
||||
}
|
||||
|
||||
Mine = async (blocks: number) => {
|
||||
await this.core.generateToAddress(blocks, this.addr)
|
||||
}
|
||||
|
||||
SendToAddress = async (address: string, amount: number) => {
|
||||
const tx = await this.core.sendToAddress(address, amount)
|
||||
console.log({ tx })
|
||||
}
|
||||
}
|
||||
108
src/tests/docker-compose.yml
Normal file
108
src/tests/docker-compose.yml
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
version: '3.3'
|
||||
services:
|
||||
backend1:
|
||||
environment:
|
||||
USERID: ${USERID:-1000}
|
||||
GROUPID: ${GROUPID:-1000}
|
||||
stop_grace_period: 5m
|
||||
image: polarlightning/bitcoind:26.0
|
||||
container_name: polar-n2-backend1
|
||||
hostname: backend1
|
||||
command: >-
|
||||
bitcoind -server=1 -regtest=1 -rpcauth=polaruser:5e5e98c21f5c814568f8b55d83b23c1c$$066b03f92df30b11de8e4b1b1cd5b1b4281aa25205bd57df9be82caf97a05526 -debug=1 -zmqpubrawblock=tcp://0.0.0.0:28334 -zmqpubrawtx=tcp://0.0.0.0:28335 -zmqpubhashblock=tcp://0.0.0.0:28336 -txindex=1 -dnsseed=0 -upnp=0 -rpcbind=0.0.0.0 -rpcallowip=0.0.0.0/0 -rpcport=18443 -rest -listen=1 -listenonion=0 -fallbackfee=0.0002 -blockfilterindex=1 -peerblockfilters=1
|
||||
volumes:
|
||||
- ./volumes/bitcoind/backend1:/home/bitcoin/.bitcoin
|
||||
expose:
|
||||
- '18443'
|
||||
- '18444'
|
||||
- '28334'
|
||||
- '28335'
|
||||
ports:
|
||||
- '18443:18443'
|
||||
- '19444:18444'
|
||||
- '28334:28334'
|
||||
- '29335:28335'
|
||||
alice:
|
||||
environment:
|
||||
USERID: ${USERID:-1000}
|
||||
GROUPID: ${GROUPID:-1000}
|
||||
stop_grace_period: 2m
|
||||
image: polarlightning/lnd:0.17.3-beta
|
||||
container_name: polar-n2-alice
|
||||
hostname: alice
|
||||
command: >-
|
||||
lnd --noseedbackup --trickledelay=5000 --alias=alice --externalip=alice --tlsextradomain=alice --tlsextradomain=polar-n2-alice --tlsextradomain=host.docker.internal --listen=0.0.0.0:9735 --rpclisten=0.0.0.0:10009 --restlisten=0.0.0.0:8080 --bitcoin.active --bitcoin.regtest --bitcoin.node=bitcoind --bitcoind.rpchost=polar-n2-backend1 --bitcoind.rpcuser=polaruser --bitcoind.rpcpass=polarpass --bitcoind.zmqpubrawblock=tcp://polar-n2-backend1:28334 --bitcoind.zmqpubrawtx=tcp://polar-n2-backend1:28335
|
||||
restart: always
|
||||
volumes:
|
||||
- ./volumes/lnd/alice:/home/lnd/.lnd
|
||||
expose:
|
||||
- '8080'
|
||||
- '10009'
|
||||
- '9735'
|
||||
ports:
|
||||
# - '8081:8080'
|
||||
- '10001:10009'
|
||||
- '9735:9735'
|
||||
bob:
|
||||
environment:
|
||||
USERID: ${USERID:-1000}
|
||||
GROUPID: ${GROUPID:-1000}
|
||||
stop_grace_period: 2m
|
||||
image: polarlightning/lnd:0.17.3-beta
|
||||
container_name: polar-n2-bob
|
||||
hostname: bob
|
||||
command: >-
|
||||
lnd --noseedbackup --trickledelay=5000 --alias=bob --externalip=bob --tlsextradomain=bob --tlsextradomain=polar-n2-bob --tlsextradomain=host.docker.internal --listen=0.0.0.0:9735 --rpclisten=0.0.0.0:10009 --restlisten=0.0.0.0:8080 --bitcoin.active --bitcoin.regtest --bitcoin.node=bitcoind --bitcoind.rpchost=polar-n2-backend1 --bitcoind.rpcuser=polaruser --bitcoind.rpcpass=polarpass --bitcoind.zmqpubrawblock=tcp://polar-n2-backend1:28334 --bitcoind.zmqpubrawtx=tcp://polar-n2-backend1:28335
|
||||
restart: always
|
||||
volumes:
|
||||
- ./volumes/lnd/bob:/home/lnd/.lnd
|
||||
expose:
|
||||
- '8080'
|
||||
- '10009'
|
||||
- '9735'
|
||||
ports:
|
||||
# - '8082:8080'
|
||||
- '10002:10009'
|
||||
- '9736:9735'
|
||||
carol:
|
||||
environment:
|
||||
USERID: ${USERID:-1000}
|
||||
GROUPID: ${GROUPID:-1000}
|
||||
stop_grace_period: 2m
|
||||
image: polarlightning/lnd:0.17.3-beta
|
||||
container_name: polar-n2-carol
|
||||
hostname: carol
|
||||
command: >-
|
||||
lnd --noseedbackup --trickledelay=5000 --alias=carol --externalip=carol --tlsextradomain=carol --tlsextradomain=polar-n2-carol --tlsextradomain=host.docker.internal --listen=0.0.0.0:9735 --rpclisten=0.0.0.0:10009 --restlisten=0.0.0.0:8080 --bitcoin.active --bitcoin.regtest --bitcoin.node=bitcoind --bitcoind.rpchost=polar-n2-backend1 --bitcoind.rpcuser=polaruser --bitcoind.rpcpass=polarpass --bitcoind.zmqpubrawblock=tcp://polar-n2-backend1:28334 --bitcoind.zmqpubrawtx=tcp://polar-n2-backend1:28335
|
||||
restart: always
|
||||
volumes:
|
||||
- ./volumes/lnd/carol:/home/lnd/.lnd
|
||||
expose:
|
||||
- '8080'
|
||||
- '10009'
|
||||
- '9735'
|
||||
ports:
|
||||
# - '8083:8080'
|
||||
- '10003:10009'
|
||||
- '9737:9735'
|
||||
dave:
|
||||
environment:
|
||||
USERID: ${USERID:-1000}
|
||||
GROUPID: ${GROUPID:-1000}
|
||||
stop_grace_period: 2m
|
||||
image: polarlightning/lnd:0.17.3-beta
|
||||
container_name: polar-n2-dave
|
||||
hostname: dave
|
||||
command: >-
|
||||
lnd --noseedbackup --trickledelay=5000 --alias=dave --externalip=dave --tlsextradomain=dave --tlsextradomain=polar-n2-dave --tlsextradomain=host.docker.internal --listen=0.0.0.0:9735 --rpclisten=0.0.0.0:10009 --restlisten=0.0.0.0:8080 --bitcoin.active --bitcoin.regtest --bitcoin.node=bitcoind --bitcoind.rpchost=polar-n2-backend1 --bitcoind.rpcuser=polaruser --bitcoind.rpcpass=polarpass --bitcoind.zmqpubrawblock=tcp://polar-n2-backend1:28334 --bitcoind.zmqpubrawtx=tcp://polar-n2-backend1:28335
|
||||
restart: always
|
||||
volumes:
|
||||
- ./volumes/lnd/dave:/home/lnd/.lnd
|
||||
expose:
|
||||
- '8080'
|
||||
- '10009'
|
||||
- '9735'
|
||||
ports:
|
||||
# - '8084:8080'
|
||||
- '10004:10009'
|
||||
- '9738:9735'
|
||||
61
src/tests/networkSetup.ts
Normal file
61
src/tests/networkSetup.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import { LoadTestSettingsFromEnv } from "../services/main/settings.js"
|
||||
import { BitcoinCoreWrapper } from "./bitcoinCore.js"
|
||||
import LND from '../services/lnd/lnd.js'
|
||||
|
||||
export const setupNetwork = async () => {
|
||||
const settings = LoadTestSettingsFromEnv()
|
||||
const core = new BitcoinCoreWrapper(settings)
|
||||
await core.InitAddress()
|
||||
await core.Mine(1)
|
||||
const alice = new LND(settings.lndSettings, () => { }, () => { }, () => { }, () => { })
|
||||
const bob = new LND({ ...settings.lndSettings, mainNode: settings.lndSettings.otherNode }, () => { }, () => { }, () => { }, () => { })
|
||||
await tryUntil<void>(async i => {
|
||||
const peers = await alice.ListPeers()
|
||||
if (peers.peers.length > 0) {
|
||||
return
|
||||
}
|
||||
await alice.ConnectPeer({ pubkey: '0232842d81b2423df97aa8a264f8c0811610a736af65afe2e145279f285625c1e4', host: "carol:9735" })
|
||||
await alice.ConnectPeer({ pubkey: '027c50fde118af534ff27e59da722422d2f3e06505c31e94c1b40c112c48a83b1c', host: "dave:9735" })
|
||||
}, 15, 2000)
|
||||
await tryUntil<void>(async i => {
|
||||
const peers = await bob.ListPeers()
|
||||
if (peers.peers.length > 0) {
|
||||
return
|
||||
}
|
||||
await bob.ConnectPeer({ pubkey: '0232842d81b2423df97aa8a264f8c0811610a736af65afe2e145279f285625c1e4', host: "carol:9735" })
|
||||
}, 15, 2000)
|
||||
|
||||
await tryUntil<void>(async i => {
|
||||
const info = await alice.GetInfo()
|
||||
if (!info.syncedToChain) {
|
||||
throw new Error("alice not synced to chain")
|
||||
}
|
||||
if (!info.syncedToGraph) {
|
||||
//await lnd.ConnectPeer({})
|
||||
throw new Error("alice not synced to graph")
|
||||
}
|
||||
}, 15, 2000)
|
||||
|
||||
await tryUntil<void>(async i => {
|
||||
const info = await bob.GetInfo()
|
||||
if (!info.syncedToChain) {
|
||||
throw new Error("bob not synced to chain")
|
||||
}
|
||||
if (!info.syncedToGraph) {
|
||||
//await lnd.ConnectPeer({})
|
||||
throw new Error("bob not synced to graph")
|
||||
}
|
||||
}, 15, 2000)
|
||||
}
|
||||
|
||||
const tryUntil = async <T>(fn: (attempt: number) => Promise<T>, maxTries: number, interval: number) => {
|
||||
for (let i = 0; i < maxTries; i++) {
|
||||
try {
|
||||
return await fn(i)
|
||||
} catch (e) {
|
||||
console.log("tryUntil error", e)
|
||||
await new Promise(resolve => setTimeout(resolve, interval))
|
||||
}
|
||||
}
|
||||
throw new Error("tryUntil failed")
|
||||
}
|
||||
BIN
src/tests/regtestNetwork.zip
Normal file
BIN
src/tests/regtestNetwork.zip
Normal file
Binary file not shown.
|
|
@ -66,8 +66,7 @@ export const SetupTest = async (d: Describe): Promise<TestBase> => {
|
|||
}
|
||||
|
||||
export const teardown = async (T: TestBase) => {
|
||||
T.main.paymentManager.watchDog.Stop()
|
||||
T.main.lnd.Stop()
|
||||
T.main.Stop()
|
||||
T.externalAccessToMainLnd.Stop()
|
||||
T.externalAccessToOtherLnd.Stop()
|
||||
T.externalAccessToThirdLnd.Stop()
|
||||
|
|
|
|||
|
|
@ -1,16 +1,27 @@
|
|||
import { globby } from 'globby'
|
||||
import { setupNetwork } from './networkSetup.js'
|
||||
import { Describe, SetupTest, teardown, TestBase } from './testBase.js'
|
||||
|
||||
|
||||
type TestModule = {
|
||||
ignore?: boolean
|
||||
dev?: boolean
|
||||
default: (T: TestBase) => Promise<void>
|
||||
}
|
||||
let failures = 0
|
||||
const start = async () => {
|
||||
const getDescribe = (fileName: string): Describe => {
|
||||
return (message, failure) => {
|
||||
if (failure) {
|
||||
failures++
|
||||
console.error(redConsole, fileName, ": FAILURE ", message, resetConsole)
|
||||
} else {
|
||||
console.log(greenConsole, fileName, ":", message, resetConsole)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const files = await globby("**/*.spec.js")
|
||||
const start = async () => {
|
||||
await setupNetwork()
|
||||
const files = await globby(["**/*.spec.js", "!**/node_modules/**"])
|
||||
const modules: { file: string, module: TestModule }[] = []
|
||||
let devModule = -1
|
||||
for (const file of files) {
|
||||
|
|
@ -19,8 +30,7 @@ const start = async () => {
|
|||
if (module.dev) {
|
||||
console.log("dev module found", file)
|
||||
if (devModule !== -1) {
|
||||
console.error(redConsole, "there are multiple dev modules", resetConsole)
|
||||
return
|
||||
throw new Error("there are multiple dev modules")
|
||||
}
|
||||
devModule = modules.length - 1
|
||||
}
|
||||
|
|
@ -28,16 +38,15 @@ const start = async () => {
|
|||
if (devModule !== -1) {
|
||||
console.log("running dev module")
|
||||
await runTestFile(modules[devModule].file, modules[devModule].module)
|
||||
return
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
console.log("running all tests")
|
||||
for (const { file, module } of modules) {
|
||||
await runTestFile(file, module)
|
||||
}
|
||||
}
|
||||
console.log(failures)
|
||||
if (failures) {
|
||||
console.error(redConsole, "there have been", `${failures}`, "failures in all tests", resetConsole)
|
||||
throw new Error("there have been " + failures + " failures in all tests")
|
||||
} else {
|
||||
console.log(greenConsole, "there have been 0 failures in all tests", resetConsole)
|
||||
}
|
||||
|
|
@ -69,16 +78,7 @@ const runTestFile = async (fileName: string, mod: TestModule) => {
|
|||
}
|
||||
}
|
||||
|
||||
const getDescribe = (fileName: string): Describe => {
|
||||
return (message, failure) => {
|
||||
if (failure) {
|
||||
failures++
|
||||
console.error(redConsole, fileName, ": FAILURE ", message, resetConsole)
|
||||
} else {
|
||||
console.log(greenConsole, fileName, ":", message, resetConsole)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const greenConsole = "\x1b[32m"
|
||||
const redConsole = "\x1b[31m"
|
||||
const resetConsole = "\x1b[0m"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { defaultInvoiceExpiry } from '../services/storage/paymentStorage.js'
|
||||
import { Describe, expect, expectThrowsAsync, runSanityCheck, safelySetUserBalance, SetupTest, TestBase } from './testBase.js'
|
||||
export const ignore = false
|
||||
export const dev = true
|
||||
export const dev = false
|
||||
export default async (T: TestBase) => {
|
||||
await safelySetUserBalance(T, T.user1, 2000)
|
||||
await testSuccessfulU2UPayment(T)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue