mirror of
https://github.com/RoboSats/robosats.git
synced 2025-09-12 21:56:29 +00:00
Merge branch 'main' into catch-chat
This commit is contained in:
@ -42,6 +42,13 @@ LND_GRPC_HOST='localhost:10009'
|
||||
|
||||
REDIS_URL='redis://localhost:6379/1'
|
||||
|
||||
# If set to True, load to console (default is False)
|
||||
# LOG_TO_CONSOLE=True
|
||||
# If set, log to file specified (LOG_TO_CONSOLE should be False)
|
||||
# LOG_FILE="<path>"
|
||||
# Change logger level (default is "WARNING")
|
||||
# LOGGER_LEVEL="WARNING"
|
||||
|
||||
# List of market price public APIs. If the currency is available in more than 1 API, will use median price.
|
||||
MARKET_PRICE_APIS = https://blockchain.info/ticker, https://api.yadio.io/exrates/BTC, https://bitpay.com/rates/BTC, https://criptoya.com/api/btc
|
||||
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -661,3 +661,6 @@ nodeapp/*.html
|
||||
|
||||
# Protocol Buffers
|
||||
api/lightning/*.proto
|
||||
|
||||
# Traditional environment
|
||||
/traditional/
|
||||
|
@ -1327,7 +1327,7 @@ class Logics:
|
||||
print(str(e))
|
||||
if "failed to connect to all addresses" in str(e):
|
||||
return False, {
|
||||
"bad_request": "The Lightning Network Daemon (LND) is down. Write in the Telegram group to make sure the staff is aware."
|
||||
"bad_request": "The lightning node is down. Write in the Telegram group to make sure the staff is aware."
|
||||
}
|
||||
elif "wallet locked" in str(e):
|
||||
return False, {
|
||||
@ -1472,7 +1472,7 @@ class Logics:
|
||||
except Exception as e:
|
||||
if "status = StatusCode.UNAVAILABLE" in str(e):
|
||||
return False, {
|
||||
"bad_request": "The Lightning Network Daemon (LND) is down. Write in the Telegram group to make sure the staff is aware."
|
||||
"bad_request": "The lightning node is down. Write in the Telegram group to make sure the staff is aware."
|
||||
}
|
||||
|
||||
take_order.taker_bond = LNPayment.objects.create(
|
||||
@ -1572,7 +1572,7 @@ class Logics:
|
||||
except Exception as e:
|
||||
if "status = StatusCode.UNAVAILABLE" in str(e):
|
||||
return False, {
|
||||
"bad_request": "The Lightning Network Daemon (LND) is down. Write in the Telegram group to make sure the staff is aware."
|
||||
"bad_request": "The lightning node is down. Write in the Telegram group to make sure the staff is aware."
|
||||
}
|
||||
|
||||
order.trade_escrow = LNPayment.objects.create(
|
||||
|
@ -27,7 +27,8 @@ class Nostr:
|
||||
|
||||
# Add relays and connect
|
||||
await client.add_relay("ws://localhost:7777")
|
||||
await client.add_relay("ws://localhost:7778")
|
||||
strfry_port = config("STRFRY_PORT", cast=str, default="7778")
|
||||
await client.add_relay(f"ws://localhost:{strfry_port}")
|
||||
await client.connect()
|
||||
|
||||
robot_name = await self.get_robot_name(order)
|
||||
|
@ -191,7 +191,7 @@ class OrderViewSchema:
|
||||
OpenApiExample(
|
||||
"When Robosats node is down",
|
||||
value={
|
||||
"bad_request": "The Lightning Network Daemon (LND) is down. Write in the Telegram group to make sure the staff is aware."
|
||||
"bad_request": "The lightning node is down. Write in the Telegram group to make sure the staff is aware."
|
||||
},
|
||||
status_codes=[400],
|
||||
),
|
||||
@ -539,7 +539,7 @@ class InfoViewSchema:
|
||||
- 24h volume
|
||||
- all time volume
|
||||
- Node info
|
||||
- lnd version
|
||||
- node version
|
||||
- node id
|
||||
- node alias
|
||||
- network
|
||||
|
@ -385,7 +385,7 @@ def compute_avg_premium(queryset):
|
||||
|
||||
def validate_pgp_keys(pub_key, enc_priv_key):
|
||||
"""Validates PGP valid keys. Formats them in a way understandable by the frontend"""
|
||||
gpg = gnupg.GPG()
|
||||
gpg = gnupg.GPG(gnupghome=config("GNUPG_DIR", default=None))
|
||||
|
||||
# Standardize format with linux linebreaks '\n'. Windows users submitting their own keys have '\r\n' breaking communication.
|
||||
enc_priv_key = enc_priv_key.replace("\r\n", "\n").replace("\\", "\n")
|
||||
@ -439,7 +439,7 @@ def verify_signed_message(pub_key, signed_message):
|
||||
Verifies a signed cleartext PGP message. Returns whether the signature
|
||||
is valid (was made by the given pub_key) and the content of the message.
|
||||
"""
|
||||
gpg = gnupg.GPG()
|
||||
gpg = gnupg.GPG(gnupghome=config("GNUPG_DIR", default=None))
|
||||
|
||||
# import the public key
|
||||
import_result = gpg.import_keys(pub_key)
|
||||
|
@ -16,6 +16,7 @@ from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from api.logics import Logics
|
||||
from api.tasks import cache_market
|
||||
from api.models import (
|
||||
Currency,
|
||||
LNPayment,
|
||||
@ -150,6 +151,9 @@ class MakerView(CreateAPIView):
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
if len(Currency.objects.all()) == 0:
|
||||
cache_market()
|
||||
|
||||
# Creates a new order
|
||||
order = Order(
|
||||
type=type,
|
||||
|
@ -20,7 +20,7 @@ _!!! Cuidado com golpistas que se passam por administradores do RoboSats. Os adm
|
||||
|
||||
- **Simplex:** [Grupo Principal do RoboSats](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2F0YuTwO05YJWS8rkjn9eLJDjQhFKvIYd8d4xG8X1blIU%3D%40smp8.simplex.im%2FyEX_vdhWew_FkovCQC3mRYRWZB1j_cBq%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAnrf9Jw3Ajdp4EQw71kqA64VgsIIzw8YNn68WjF09jFY%253D%26srv%3Dbeccx4yfxxbvyhqypaavemqurytl6hozr47wfc7uuecacjqdvwpw2xid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22hWnMVPnJl-KT3-virDk0JA%3D%3D%22%7D). Tem perguntas ou um problema? Encontre suporte comunitário na conversa pública do grupo SimpleX. Se você quer se juntar a outros robôs legais e aprender mais sobre o RoboSats, então essas discussões acontecem no SimpleX, Nostr e nos grupos de chat Matrix.
|
||||
|
||||
- **Nostr:** [Grupo Geral do RoboSats](https://snort.social/e/note1tfwvglg8xz8420pfgav0dc9mqekv02nkpck2axefklrema7lk6wszmwxdy). Junte-se a outros robôs legais e não hesite em fazer perguntas sobre o RoboSats! Além disso, a conta [RoboSats Nostr](npub1p2psats79rypr8lpnl9t5qdekfp700x660qsgw284xvq4s09lqrqqk3m82) fornece atualizações importantes do projeto, dicas e truques de uso do RoboSats, e outros comentários centrados na privacidade. Perguntas e interações são bem-vindas. Lembre-se: problemas que exigem suporte da equipe do RoboSats devem ser direcionados para o grupo principal do SimpleX, onde as respostas são mais rápidas e a equipe pode investigar mais a fundo o seu problema.
|
||||
- **Nostr:** [Grupo Geral do RoboSats](https://snort.social/e/note1tfwvglg8xz8420pfgav0dc9mqekv02nkpck2axefklrema7lk6wszmwxdy). Junte-se a outros robôs legais e não hesite em fazer perguntas sobre o RoboSats! Além disso, a conta [RoboSats Nostr](nprofile1qqsyx53h3h7ec4fwlspjq0kqec5gv54t7rc48xdtq6q4y94wsw4fnjqsg3jtv) fornece atualizações importantes do projeto, dicas e truques de uso do RoboSats, e outros comentários centrados na privacidade. Perguntas e interações são bem-vindas. Lembre-se: problemas que exigem suporte da equipe do RoboSats devem ser direcionados para o grupo principal do SimpleX, onde as respostas são mais rápidas e a equipe pode investigar mais a fundo o seu problema.
|
||||
|
||||
- **Matrix:** [Grupo de Desenvolvimento do RoboSats](https://matrix.to/#/#robosats:matrix.org). Grupo de chat principal de comunicação entre desenvolvedores, onde discussões abertas e técnicas sobre o desenvolvimento ocorrem. Discussões sobre mudanças de código acontecem em issues e pull requests (PRs) do GitHub.
|
||||
|
||||
|
@ -162,7 +162,7 @@ paths:
|
||||
- 24h volume
|
||||
- all time volume
|
||||
- Node info
|
||||
- lnd version
|
||||
- node version
|
||||
- node id
|
||||
- node alias
|
||||
- network
|
||||
@ -419,7 +419,7 @@ paths:
|
||||
summary: When maker bond expires (as maker)
|
||||
WhenRobosatsNodeIsDown:
|
||||
value:
|
||||
bad_request: The Lightning Network Daemon (LND) is down. Write
|
||||
bad_request: The lightning node is down. Write
|
||||
in the Telegram group to make sure the staff is aware.
|
||||
summary: When Robosats node is down
|
||||
description: ''
|
||||
|
1920
frontend/package-lock.json
generated
1920
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -15,29 +15,29 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.27.1",
|
||||
"@babel/plugin-transform-runtime": "^7.27.1",
|
||||
"@babel/core": "^7.27.3",
|
||||
"@babel/plugin-transform-runtime": "^7.27.3",
|
||||
"@babel/preset-env": "^7.27.2",
|
||||
"@babel/preset-react": "^7.27.1",
|
||||
"@babel/preset-typescript": "^7.27.1",
|
||||
"@babel/runtime": "^7.27.1",
|
||||
"@babel/runtime": "^7.27.3",
|
||||
"@eslint/compat": "^1.2.9",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "^9.26.0",
|
||||
"@eslint/js": "^9.27.0",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/latlon-geohash": "^2.0.4",
|
||||
"@types/leaflet": "^1.9.17",
|
||||
"@types/react": "^19.1.3",
|
||||
"@types/react-dom": "^19.1.3",
|
||||
"@types/leaflet": "^1.9.18",
|
||||
"@types/react": "^19.1.6",
|
||||
"@types/react-dom": "^19.1.5",
|
||||
"@types/webpack": "^5.28.5",
|
||||
"@typescript-eslint/eslint-plugin": "^8.32.0",
|
||||
"@typescript-eslint/parser": "^8.32.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.33.0",
|
||||
"@typescript-eslint/parser": "^8.33.0",
|
||||
"babel-loader": "^10.0.0",
|
||||
"css-loader": "^7.1.2",
|
||||
"eslint": "^9.26.0",
|
||||
"eslint": "^9.27.0",
|
||||
"eslint-config-love": "^120.0.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-import-resolver-typescript": "^4.3.4",
|
||||
"eslint-import-resolver-typescript": "^4.4.1",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-n": "^17.18.0",
|
||||
"eslint-plugin-prettier": "^5.4.0",
|
||||
@ -45,19 +45,18 @@
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"filemanager-webpack-plugin": "^8.0.0",
|
||||
"globals": "^16.1.0",
|
||||
"globals": "^16.2.0",
|
||||
"html-webpack-plugin": "^5.6.3",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.5.3",
|
||||
"style-loader": "^4.0.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.8.3",
|
||||
"webpack": "^5.99.8",
|
||||
"webpack": "^5.99.9",
|
||||
"webpack-cli": "^6.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@christopherpickering/react-leaflet-markercluster": "^1.1.0",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/base": "^5.0.0-beta.70",
|
||||
@ -65,34 +64,35 @@
|
||||
"@mui/lab": "^7.0.0-beta.12",
|
||||
"@mui/material": "^7.1.0",
|
||||
"@mui/system": "^7.1.0",
|
||||
"@mui/x-data-grid": "^8.3.1",
|
||||
"@mui/x-date-pickers": "^8.3.0",
|
||||
"@nivo/core": "^0.96.0",
|
||||
"@nivo/line": "^0.96.0",
|
||||
"@mui/x-data-grid": "^8.4.0",
|
||||
"@mui/x-date-pickers": "^8.4.0",
|
||||
"@nivo/core": "^0.99.0",
|
||||
"@nivo/line": "^0.99.0",
|
||||
"base-ex": "^0.8.1",
|
||||
"country-flag-icons": "^1.5.19",
|
||||
"date-fns": "^4.1.0",
|
||||
"file-replace-loader": "^1.4.2",
|
||||
"i18next": "^25.1.2",
|
||||
"i18next": "^25.2.1",
|
||||
"i18next-browser-languagedetector": "^8.1.0",
|
||||
"i18next-http-backend": "^3.0.2",
|
||||
"install": "^0.13.0",
|
||||
"js-sha256": "^0.11.0",
|
||||
"js-sha256": "^0.11.1",
|
||||
"latlon-geohash": "^2.0.0",
|
||||
"leaflet": "^1.9.4",
|
||||
"light-bolt11-decoder": "^3.2.0",
|
||||
"nostr-tools": "^2.13.0",
|
||||
"npm": "^11.3.0",
|
||||
"npm": "^11.4.1",
|
||||
"openpgp": "^5.11.0",
|
||||
"react": "^18.3.0",
|
||||
"react": "^19.1.0",
|
||||
"react-countdown": "^2.3.6",
|
||||
"react-dom": "^18.3.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-grid-layout": "^1.5.1",
|
||||
"react-i18next": "^15.5.1",
|
||||
"react-i18next": "^15.5.2",
|
||||
"react-image": "^4.1.0",
|
||||
"react-leaflet": "^4.2.1",
|
||||
"react-leaflet": "^5.0.0",
|
||||
"react-leaflet-markercluster": "^5.0.0-rc.0",
|
||||
"react-qr-code": "^2.0.15",
|
||||
"react-router-dom": "^7.6.0",
|
||||
"react-router-dom": "^7.6.1",
|
||||
"react-smooth-image": "^1.1.0",
|
||||
"react-world-flags": "^1.6.0",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
|
@ -26,7 +26,6 @@ interface Props {
|
||||
|
||||
const CommunityDialog = ({ open = false, onClose }: Props): React.JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
const [client] = window.RobosatsSettings.split('-');
|
||||
|
||||
const flagProps = {
|
||||
width: 30,
|
||||
@ -81,16 +80,11 @@ const CommunityDialog = ({ open = false, onClose }: Props): React.JSX.Element =>
|
||||
<ListItemButton
|
||||
component='a'
|
||||
onClick={() => {
|
||||
if (client === 'mobile') {
|
||||
window.location.href =
|
||||
'nostr:npub1p2psats79rypr8lpnl9t5qdekfp700x660qsgw284xvq4s09lqrqqk3m82';
|
||||
} else {
|
||||
window.open(
|
||||
'https://njump.me/npub1p2psats79rypr8lpnl9t5qdekfp700x660qsgw284xvq4s09lqrqqk3m82',
|
||||
'_blank',
|
||||
'noopener,noreferrer',
|
||||
);
|
||||
}
|
||||
window.open(
|
||||
'https://njump.me/nprofile1qqsyx53h3h7ec4fwlspjq0kqec5gv54t7rc48xdtq6q4y94wsw4fnjqsg3jtv',
|
||||
'_blank',
|
||||
'noopener,noreferrer',
|
||||
);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
|
@ -488,7 +488,7 @@ const MakerForm = ({
|
||||
if (pos != null) handleAddLocation(pos);
|
||||
setOpenWorldmap(false);
|
||||
}}
|
||||
zoom={maker.latitude != null && maker.longitude != null ? 6 : undefined}
|
||||
zoom={maker.latitude === 0 && maker.longitude === 0 ? 2 : 6}
|
||||
/>
|
||||
<Collapse in={!(Object.keys(limits).lenght === 0 || collapseAll)}>
|
||||
<Grid container justifyContent='space-between' spacing={0} sx={{ maxHeight: '1em' }}>
|
||||
|
@ -4,7 +4,7 @@ import { useTheme, LinearProgress } from '@mui/material';
|
||||
import { DivIcon, type LeafletMouseEvent } from 'leaflet';
|
||||
import { type PublicOrder } from '../../models';
|
||||
import OrderTooltip from '../Charts/helpers/OrderTooltip';
|
||||
import MarkerClusterGroup from '@christopherpickering/react-leaflet-markercluster';
|
||||
import MarkerClusterGroup from 'react-leaflet-markercluster';
|
||||
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
||||
|
||||
interface MapPinProps {
|
||||
|
@ -248,6 +248,7 @@ const SettingsForm = ({ dense = false }: SettingsFormProps): React.JSX.Element =
|
||||
</ListItemIcon>
|
||||
<ToggleButtonGroup
|
||||
exclusive={true}
|
||||
sx={{ width: '100%' }}
|
||||
value={settings.useProxy}
|
||||
onChange={(_e, useProxy) => {
|
||||
setSettings({ ...settings, useProxy });
|
||||
|
@ -82,7 +82,9 @@ const EncryptedChat: React.FC<Props> = ({
|
||||
|
||||
const wrappedEvent = nip17.wrapEvent(slot?.nostrSecKey, recipient, content);
|
||||
|
||||
wrappedEvent.tags.push(['expiration', (wrappedEvent.created_at + 2419200).toString()]);
|
||||
const oneMonth = 2419200;
|
||||
|
||||
wrappedEvent.tags.push(['expiration', (wrappedEvent.created_at + oneMonth).toString()]);
|
||||
|
||||
federation.roboPool.sendEvent(wrappedEvent);
|
||||
} catch (error) {
|
||||
|
@ -251,7 +251,7 @@ export const AppContextProvider = ({ children }: AppContextProviderProps): React
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (page === 'offers' && !worldmap) {
|
||||
if (['offers', 'create'].includes(page) && !worldmap) {
|
||||
getWorldmapGeojson(apiClient, hostUrl)
|
||||
.then((data) => {
|
||||
setWorldmap(data);
|
||||
|
@ -769,8 +769,6 @@ svg.leaflet-image-layer.leaflet-interactive path {
|
||||
}
|
||||
}
|
||||
|
||||
/* react-leaflet-cluster https://unpkg.com/@christopherpickering/react-leaflet-markercluster@1.1.0/dist/styles.min.css */
|
||||
|
||||
.marker-cluster-small {
|
||||
background-color: rgba(181, 226, 140, 0.6);
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
django==5.1.4
|
||||
django==5.1.9
|
||||
django-admin-relation-links==0.2.5
|
||||
django-celery-beat==2.7.0
|
||||
django-celery-beat==2.8.1
|
||||
django-celery-results==2.6.0
|
||||
django-model-utils==5.0.0
|
||||
django-redis==5.4.0
|
||||
djangorestframework==3.15.2
|
||||
djangorestframework==3.16.0
|
||||
channels==4.2.0
|
||||
channels-redis==4.2.1
|
||||
celery==5.4.0
|
||||
celery==5.5.2
|
||||
grpcio==1.67.0
|
||||
googleapis-common-protos==1.70.0
|
||||
grpcio-tools==1.67.0
|
||||
@ -21,11 +21,11 @@ psycopg2==2.9.10
|
||||
SQLAlchemy==2.0.16
|
||||
django-import-export==4.3.7
|
||||
requests[socks]
|
||||
shapely==2.0.6
|
||||
shapely==2.0.7
|
||||
python-gnupg==0.5.3
|
||||
daphne==4.1.2
|
||||
drf-spectacular==0.28.0
|
||||
drf-spectacular-sidecar==2024.12.1
|
||||
drf-spectacular-sidecar==2025.5.1
|
||||
django-cors-headers==4.7.0
|
||||
base91==1.0.1
|
||||
nostr-sdk==0.35.1
|
||||
|
@ -1,4 +1,5 @@
|
||||
coverage==7.8.0
|
||||
ruff==0.11.10
|
||||
git+https://github.com/Reckless-Satoshi/drf-openapi-tester.git@soften-django-requirements
|
||||
pre-commit==4.0.1
|
||||
pre-commit==4.2.0
|
||||
python-dotenv[cli]==1.1.0
|
||||
|
@ -12,7 +12,6 @@ https://docs.djangoproject.com/en/4.0/ref/settings/
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
@ -59,7 +58,7 @@ CORS_ALLOW_ALL_ORIGINS = True
|
||||
SESSION_COOKIE_HTTPONLY = False
|
||||
|
||||
# Logging settings
|
||||
if os.environ.get("LOG_TO_CONSOLE"):
|
||||
if config("LOG_TO_CONSOLE", cast=bool, default=False):
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
@ -70,12 +69,33 @@ if os.environ.get("LOG_TO_CONSOLE"):
|
||||
},
|
||||
"root": {
|
||||
"handlers": ["console"],
|
||||
"level": "WARNING",
|
||||
"level": config("LOGGER_LEVEL", cast=str, default="WARNING"),
|
||||
},
|
||||
"loggers": {
|
||||
"api.utils": {
|
||||
"handlers": ["console"],
|
||||
"level": "WARNING",
|
||||
"level": config("LOGGER_LEVEL", cast=str, default="WARNING"),
|
||||
},
|
||||
},
|
||||
}
|
||||
elif config("LOG_FILE", False):
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"handlers": {
|
||||
"file": {
|
||||
"class": "logging.FileHandler",
|
||||
"filename": config("LOG_FILE", cast=str),
|
||||
},
|
||||
},
|
||||
"root": {
|
||||
"handlers": ["file"],
|
||||
"level": config("LOGGER_LEVEL", cast=str, default="WARNING"),
|
||||
},
|
||||
"loggers": {
|
||||
"api.utils": {
|
||||
"handlers": ["file"],
|
||||
"level": config("LOGGER_LEVEL", cast=str, default="WARNING"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
277
scripts/traditional/README.md
Normal file
277
scripts/traditional/README.md
Normal file
@ -0,0 +1,277 @@
|
||||
# Robosats traditional environment
|
||||
|
||||
Robosats backend development and testing without docker and containers.
|
||||
|
||||
Binaries needed:
|
||||
* postgresql (`postgres`, `initdb`, `psql`)
|
||||
* redis (`redis-server`)
|
||||
* bitcoin (`bitcoind`, `bitcoin-cli`)
|
||||
* cln (`lightningd`, `lightning-cli`, `holdinvoice`)
|
||||
* lnd (`lnd`, `lncli`)
|
||||
|
||||
## Preparation
|
||||
|
||||
Postgresql and redis can be found in all linux distros and bsds.
|
||||
|
||||
Some distros do not put postgresql binaries in `PATH`, if this is the
|
||||
case simply link them somewhere in your `PATH`.
|
||||
|
||||
Example on debian:
|
||||
```
|
||||
ln -sf /usr/lib/postgresql/16/bin/postgres ~/.local/bin/
|
||||
ln -sf /usr/lib/postgresql/16/bin/initdb ~/.local/bin/
|
||||
ln -sf /usr/lib/postgresql/16/bin/psql ~/.local/bin/
|
||||
```
|
||||
|
||||
Bitcoin nodes if not already installed need to be manually downloaded.
|
||||
* bitcoin core binaries can be found here: https://bitcoincore.org/en/download
|
||||
* cln binaries can be found here: https://github.com/ElementsProject/lightning/releases
|
||||
* holdinvoice binary can be found here: https://github.com/daywalker90/holdinvoice/releases
|
||||
* lnd binaries can be found here: https://github.com/lightningnetwork/lnd/releases
|
||||
|
||||
Example preparation:
|
||||
```
|
||||
$ python3 -m venv venv
|
||||
$ . venv/bin/activate
|
||||
$ pip install -r requirements_dev.txt
|
||||
$ pip install -r requirements.txt
|
||||
|
||||
$ mkdir traditional
|
||||
$ mkdir traditional/programs
|
||||
$ cd traditional/programs
|
||||
|
||||
# if you do not have them already installed
|
||||
$ mkdir bitcoin cln lnd
|
||||
# download bitcoin, cln (and holdinvoice) and lnd binaries
|
||||
|
||||
# follow https://github.com/hoytech/strfry#compile
|
||||
$ git clone https://github.com/hoytech/strfry
|
||||
$ cd strfry
|
||||
$ git submodule update --init
|
||||
$ git checkout 1.0.4
|
||||
$ make setup-golpe
|
||||
$ make -j4
|
||||
|
||||
# if you want to use roboauto
|
||||
# still in traditional/programs
|
||||
$ git clone https://github.com/jerryfletcher21/roboauto
|
||||
$ cd roboauto
|
||||
$ pip install -r requirements.txt
|
||||
$ pip install .
|
||||
```
|
||||
|
||||
## env file
|
||||
|
||||
```
|
||||
$ cp .env-sample .env
|
||||
```
|
||||
Edit `.env`, both robosats and traditional scripts will read from there.
|
||||
|
||||
Variables to change:
|
||||
```
|
||||
LNVENDOR = "CLN"
|
||||
# LNVENDOR = "LND"
|
||||
|
||||
BITCOIND_RPCURL = "http://127.0.0.1:18443"
|
||||
BITCOIND_RPCUSER = "test"
|
||||
BITCOIND_RPCPASSWORD = "test"
|
||||
CLN_DIR = "traditional/nodes/cln-coord/regtest/"
|
||||
CLN_GRPC_HOST = "localhost:9999"
|
||||
CLN_GRPC_HOLD_HOST = "localhost:9998"
|
||||
LND_DIR = "traditional/nodes/lnd-coord/"
|
||||
MACAROON_PATH = "data/chain/bitcoin/regtest/admin.macaroon"
|
||||
LND_GRPC_HOST = "localhost:10009"
|
||||
# POSTGRES_DB should not be postgres
|
||||
POSTGRES_DB = "robosats"
|
||||
# POSTGRES_USER should not be the same as $USER environment variable
|
||||
POSTGRES_USER = "robosats"
|
||||
POSTGRES_PASSWORD = "robosats"
|
||||
USE_TOR = False
|
||||
LOG_TO_CONSOLE = True
|
||||
LOGGER_LEVEL = "INFO"
|
||||
```
|
||||
|
||||
Variables to add:
|
||||
```
|
||||
DEVELOPMENT = True
|
||||
TESTING = True
|
||||
SKIP_FRONTEND_TESTS = True
|
||||
TIMING_EXTRA_IN_TESTS = True
|
||||
|
||||
# LNVENDOR_USER is what robosats calls robot node in tests
|
||||
LNVENDOR_USER = "LND"
|
||||
# LNVENDOR_USER = "CLN"
|
||||
|
||||
DAPHNE_PORT = 9000
|
||||
GUNICORN_PORT = 8080
|
||||
RUNSERVER_PORT = 8000
|
||||
STRFRY_PORT = 7778
|
||||
|
||||
BITCOIND_BIN = "traditional/programs/bitcoin/bin/bitcoind"
|
||||
BITCOIN_CLI_BIN = "traditional/programs/bitcoin/bin/bitcoin-cli"
|
||||
LIGHTNINGD_BIN = "traditional/programs/cln/bin/lightningd"
|
||||
LIGHTNING_CLI_BIN = "traditional/programs/cln/bin/lightning-cli"
|
||||
HOLDINVOICE_PLUGIN_BIN = "traditional/programs/cln/holdinvoice"
|
||||
LND_BIN = "traditional/programs/lnd/lnd"
|
||||
LNCLI_BIN = "traditional/programs/lnd/lncli"
|
||||
STRFRY_GIT_DIR = "traditional/programs/strfry"
|
||||
ROBOAUTO_GIT_DIR = "traditional/programs/roboauto"
|
||||
TRADITIONAL_NODES_DIR = "traditional/nodes"
|
||||
TRADITIONAL_SERVICES_DIR = "traditional/services"
|
||||
TRADITIONAL_LOGS_DIR = "traditional/logs"
|
||||
GNUPG_DIR = "traditional/services/gnupg"
|
||||
|
||||
BITCOIN_TEST_ZMQ_BLOCK_PORT = 28432
|
||||
BITCOIN_TEST_ZMQ_TX_PORT = 28433
|
||||
|
||||
# CLN_GRPC_HOST and CLN_GRPC_HOLD_HOST are for coord
|
||||
CLN_TEST_COORD_LISTEN_PORT = 19846
|
||||
CLN_TEST_USER_GRPC_PORT = 9989
|
||||
CLN_TEST_USER_LISTEN_PORT = 19836
|
||||
|
||||
# LND_GRPC_HOST is for coord
|
||||
LND_TEST_COORD_LISTEN_PORT = 19746
|
||||
LND_TEST_COORD_REST_PORT = 8181
|
||||
LND_TEST_COORD_MACAROON_PATH = "traditional/nodes/lnd-coord/data/chain/bitcoin/regtest/admin.macaroon"
|
||||
|
||||
LND_TEST_USER_GRPC_PORT = 10010
|
||||
LND_TEST_USER_LISTEN_PORT = 19736
|
||||
LND_TEST_USER_REST_PORT = 8182
|
||||
LND_TEST_USER_MACAROON_PATH = "traditional/nodes/lnd-user/data/chain/bitcoin/regtest/admin.macaroon"
|
||||
```
|
||||
|
||||
Paths can be relative or absolute. Binaries should be paths, they are
|
||||
not resolved with `PATH`.
|
||||
|
||||
Roboauto can be disabled by not setting `ROBOAUTO_GIT_DIR` or setting it
|
||||
to `false`.
|
||||
|
||||
If some ports are already in use, change their value.
|
||||
|
||||
To check which port are already in use, `netstat -tulnp` with root
|
||||
privileges can be used.
|
||||
|
||||
For example if there is alread an instance of postgresql running on the
|
||||
default port, change `POSTGRES_PORT = "5433"`.
|
||||
|
||||
## Usage
|
||||
|
||||
For development and testing two scripts are provided:
|
||||
* `traditional-services` for non bitcoin related services
|
||||
* `regtest-nodes` for bitcoin and lightning nodes
|
||||
|
||||
`traditional-services` sets up the database and manages the services.
|
||||
|
||||
Everything is done locally, so no root privileges/service managers are
|
||||
needed.
|
||||
|
||||
`regtest-nodes` is a script that should be sourced, it sets up a regtest
|
||||
environment, with bitcoin core, cln, lnd and roboauto, connecting them
|
||||
and creating channels. It then exposes the functions `btc_reg`,
|
||||
`cln_coord`, `cln_user`, `lnd_coord`, `lnd_user`, `ra_reg` to interact
|
||||
with the nodes and roboauto.
|
||||
|
||||
If the script is sourced in a `bash` shell, it will also source
|
||||
completions for all the functions.
|
||||
|
||||
`regtest-nodes` can also be run without arguments to simply expose the
|
||||
functions to start and remove the nodes and to create the channels
|
||||
between them, without setting up a specific environment.
|
||||
|
||||
Setup:
|
||||
```
|
||||
# change .env file
|
||||
|
||||
$ . venv/bin/activate
|
||||
|
||||
# generate cln and lnd grpc
|
||||
$ scripts/generate_grpc.sh
|
||||
|
||||
$ . scripts/traditional/regtest-nodes test
|
||||
|
||||
$ scripts/traditional/traditional-services postgres-setup
|
||||
|
||||
$ scripts/traditional/traditional-services postgres-database
|
||||
|
||||
$ scripts/traditional/traditional-services strfry-setup
|
||||
|
||||
# remove the nodes
|
||||
$ robosats_regtest_stop_and_remove_all
|
||||
|
||||
# postgres-database will create the database specified by
|
||||
# POSTGRES_DB in .env, it can be run multiple times with
|
||||
# different values of POSTGRES_DB for different databases
|
||||
```
|
||||
|
||||
Testing:
|
||||
```
|
||||
# edit .env setting LNVENDOR to either "CLN" or "LND"
|
||||
# LNVENDOR_USER while running tests should be set to "LND"
|
||||
|
||||
# in the main window
|
||||
$ . venv/bin/activate
|
||||
$ . scripts/traditional/regtest-nodes test
|
||||
|
||||
# in a secondary window
|
||||
$ . venv/bin/activate
|
||||
# can be stopped with Control-C
|
||||
$ scripts/traditional/traditional-services test
|
||||
|
||||
# back in the main window
|
||||
$ python3 manage.py test
|
||||
|
||||
# after having run the tests run
|
||||
$ robosats_regtest_stop_and_remove_all
|
||||
# to remove the nodes, they will be recreated when
|
||||
# running the tests again
|
||||
|
||||
# python3 manage.py test can be run multiple times with the same database
|
||||
# to have a clean database either use a different value
|
||||
# of POSTGRES_DB or use a different directory (and run again the setup)
|
||||
# by moving traditional/services/postgres somewhere and the moving it back when
|
||||
# you want to use the old database again
|
||||
```
|
||||
|
||||
Development:
|
||||
```
|
||||
# edit .env setting LNVENDOR to either "CLN" or "LND"
|
||||
# and LNVENDOR_USER to either "CLN" or "LND"
|
||||
|
||||
# in the main window
|
||||
$ . venv/bin/activate
|
||||
$ . scripts/traditional/regtest-nodes server
|
||||
|
||||
# in a secondary window
|
||||
$ . venv/bin/activate
|
||||
# can be stopped with Control-C
|
||||
$ scripts/traditional/traditional-services server
|
||||
|
||||
# to see the output of the django runserver command
|
||||
# in a third window
|
||||
$ tail -f traditional/logs/runserver
|
||||
|
||||
# if roboauto is active, use it to test the backend
|
||||
# back in the main window
|
||||
$ ra_reg --help
|
||||
...
|
||||
$ ra_reg create-order "$(ra_reg generate-robot --loc)" type=buy currency=btc min_amount=0.001 max_amount=0.002 payment_method="On-Chain BTC" premium=-1.5
|
||||
...
|
||||
$ ra_reg take-order $(ra_reg generate-robot --loc) order-id
|
||||
...
|
||||
$ ra_reg escrow-pay RobotName
|
||||
...
|
||||
```
|
||||
|
||||
Update:
|
||||
```
|
||||
$ . venv/bin/activate
|
||||
|
||||
$ pip install -r requirements_dev.txt
|
||||
$ pip install -r requirements.txt
|
||||
|
||||
# start just postgres and redis in an other window
|
||||
$ scripts/traditional/traditional-services test
|
||||
|
||||
# in the main window
|
||||
$ python3 manage.py migrate
|
||||
```
|
1438
scripts/traditional/regtest-nodes
Executable file
1438
scripts/traditional/regtest-nodes
Executable file
File diff suppressed because it is too large
Load Diff
281
scripts/traditional/robosats.bash-completion
Executable file
281
scripts/traditional/robosats.bash-completion
Executable file
@ -0,0 +1,281 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# adapted from
|
||||
# https://github.com/bitcoin/bitcoin/blob/master/contrib/completions/bash/bitcoin-cli.bash
|
||||
_bitcoin_cli() {
|
||||
local cur prev words=() cword
|
||||
local bitcoin_cli
|
||||
|
||||
# save and use original argument to invoke bitcoin-cli for -help, help and RPC
|
||||
# as bitcoin-cli might not be in $PATH
|
||||
bitcoin_cli="$1"
|
||||
|
||||
if ! command -v "$bitcoin_cli" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
COMPREPLY=()
|
||||
_get_comp_words_by_ref -n = cur prev words cword
|
||||
|
||||
if ((cword > 5)); then
|
||||
case ${words[cword-5]} in
|
||||
sendtoaddress)
|
||||
# shellcheck disable=SC2207
|
||||
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if ((cword > 4)); then
|
||||
case ${words[cword-4]} in
|
||||
importaddress|listtransactions|setban)
|
||||
# shellcheck disable=SC2207
|
||||
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
|
||||
return 0
|
||||
;;
|
||||
signrawtransactionwithkey|signrawtransactionwithwallet)
|
||||
# shellcheck disable=SC2207
|
||||
COMPREPLY=( $( compgen -W "ALL NONE SINGLE ALL|ANYONECANPAY NONE|ANYONECANPAY SINGLE|ANYONECANPAY" -- "$cur" ) )
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if ((cword > 3)); then
|
||||
case ${words[cword-3]} in
|
||||
addmultisigaddress)
|
||||
return 0
|
||||
;;
|
||||
getbalance|gettxout|importaddress|importpubkey|importprivkey|listreceivedbyaddress|listsinceblock)
|
||||
# shellcheck disable=SC2207
|
||||
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if ((cword > 2)); then
|
||||
case ${words[cword-2]} in
|
||||
addnode)
|
||||
# shellcheck disable=SC2207
|
||||
COMPREPLY=( $( compgen -W "add remove onetry" -- "$cur" ) )
|
||||
return 0
|
||||
;;
|
||||
setban)
|
||||
# shellcheck disable=SC2207
|
||||
COMPREPLY=( $( compgen -W "add remove" -- "$cur" ) )
|
||||
return 0
|
||||
;;
|
||||
fundrawtransaction|getblock|getblockheader|getmempoolancestors|getmempooldescendants|getrawtransaction|gettransaction|listreceivedbyaddress|sendrawtransaction)
|
||||
# shellcheck disable=SC2207
|
||||
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
case "$prev" in
|
||||
backupwallet|dumpwallet|importwallet)
|
||||
_filedir
|
||||
return 0
|
||||
;;
|
||||
getaddednodeinfo|getrawmempool|lockunspent)
|
||||
# shellcheck disable=SC2207
|
||||
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
|
||||
return 0
|
||||
;;
|
||||
getbalance|getnewaddress|listtransactions|sendmany)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# determine already specified args necessary for RPC
|
||||
local rpcargs=()
|
||||
local i
|
||||
for i in ${COMP_LINE}; do
|
||||
case "$i" in
|
||||
-conf=*|-datadir=*|-rpc*|-chain=*|-testnet|-signet|-regtest)
|
||||
rpcargs=( "${rpcargs[@]}" "$i" )
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
case "$cur" in
|
||||
-conf=*)
|
||||
cur="${cur#*=}"
|
||||
_filedir
|
||||
return 0
|
||||
;;
|
||||
-datadir=*)
|
||||
cur="${cur#*=}"
|
||||
_filedir -d
|
||||
return 0
|
||||
;;
|
||||
-rpcwallet=*)
|
||||
cur="${cur#*=}"
|
||||
wallets="$($bitcoin_cli "${rpcargs[@]}" listwallets | jq -r '.[]')"
|
||||
# shellcheck disable=SC2207
|
||||
COMPREPLY=( $( compgen -W "$wallets" -- "$cur" ) )
|
||||
return 0
|
||||
;;
|
||||
-*=*) # prevent nonsense completions
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
local helpopts commands completions
|
||||
|
||||
# only parse -help if senseful
|
||||
if [[ -z "$cur" || "$cur" =~ ^- ]]; then
|
||||
helpopts=$($bitcoin_cli -help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' )
|
||||
fi
|
||||
|
||||
# only parse help if senseful
|
||||
if [[ -z "$cur" || "$cur" =~ ^[a-z] ]]; then
|
||||
commands=$($bitcoin_cli "${rpcargs[@]}" help 2>/dev/null | awk '$1 ~ /^[a-z]/ { print $1; }')
|
||||
fi
|
||||
|
||||
completions="$helpopts $commands generatetoaddress"
|
||||
|
||||
# shellcheck disable=SC2207
|
||||
COMPREPLY=( $( compgen -W "$completions" -- "$cur" ) )
|
||||
|
||||
# Prevent space if an argument is desired
|
||||
local word
|
||||
for word in "${COMPREPLY[@]}"; do
|
||||
case "$word" in
|
||||
*=)
|
||||
compopt -o nospace
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
} &&
|
||||
complete -F _bitcoin_cli btc_reg
|
||||
|
||||
# adapted from
|
||||
# https://github.com/ElementsProject/lightning/blob/master/contrib/lightning-cli.bash-completion
|
||||
_lightning_cli() {
|
||||
local command_name="$1"
|
||||
# local current_word="$2"
|
||||
local previous_word="$3"
|
||||
|
||||
local lightning_cli
|
||||
|
||||
# lightning_cli might not be in $PATH
|
||||
lightning_cli="$command_name"
|
||||
|
||||
if ! command -v "$lightning_cli" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "${COMP_CWORD}" -eq 1 ]; then
|
||||
complete_opt=true
|
||||
else
|
||||
case "$previous_word" in
|
||||
--help|-h) complete_opt=false ;;
|
||||
help|-*) complete_opt=true ;;
|
||||
*) complete_opt=false ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "$complete_opt" = true ]; then
|
||||
# shellcheck disable=SC2034
|
||||
local cur prev words=() cword
|
||||
|
||||
COMPREPLY=()
|
||||
_get_comp_words_by_ref -n = cur prev words cword
|
||||
|
||||
case "$cur" in
|
||||
-*=*) # prevent nonsense completions
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
local helpopts globalcmds
|
||||
|
||||
# get the global options, starting with --
|
||||
if [[ -z "$cur" || "$cur" =~ ^- ]]; then
|
||||
globalcmds="$(
|
||||
$lightning_cli --help 2>&1 |
|
||||
tr '|' '\n' |
|
||||
sed -n -e 's/ .*//' -e 's/\(-[-a-z0-9A-Z]*\).*/\1/p'
|
||||
)"
|
||||
fi
|
||||
|
||||
# get the regular commands
|
||||
if [[ -z "$cur" || "$cur" =~ ^[a-z] ]]; then
|
||||
helpopts="$(
|
||||
$lightning_cli help 2>/dev/null |
|
||||
sed -n 's/^\([a-z][a-z_-]*\).*/\1/p' |
|
||||
sed '$ d'
|
||||
)"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2207
|
||||
COMPREPLY=( $( compgen -W "$helpopts $globalcmds" -X "*," -- "$cur" ) )
|
||||
;;
|
||||
esac
|
||||
else
|
||||
_minimal
|
||||
fi
|
||||
} &&
|
||||
complete -F _lightning_cli cln_coord &&
|
||||
complete -F _lightning_cli cln_user
|
||||
|
||||
# adapted from
|
||||
# https://github.com/lightningnetwork/lnd/blob/master/contrib/lncli.bash-completion
|
||||
_lncli() {
|
||||
local cur prev words=() cword
|
||||
local lncli
|
||||
|
||||
# lncli might not be in $PATH
|
||||
lncli="$1"
|
||||
|
||||
if ! command -v "$lncli" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
COMPREPLY=()
|
||||
_get_comp_words_by_ref -n = cur prev words cword
|
||||
|
||||
case "$prev" in
|
||||
# example of further completion
|
||||
newaddress)
|
||||
# shellcheck disable=SC2207
|
||||
COMPREPLY=( $( compgen -W "p2wkh np2wkh" -- "$cur" ) )
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$cur" in
|
||||
-*=*) # prevent nonsense completions
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$cword" -eq 1 ] || {
|
||||
[ "$cword" -eq 2 ] && [ "$prev" = "help" ]
|
||||
}; then
|
||||
local helpopts globalcmds completions
|
||||
|
||||
# get the global options, starting with --
|
||||
if [[ -z "$cur" || "$cur" =~ ^- ]]; then
|
||||
globalcmds=$($lncli help 2>&1 | awk '$1 ~ /^-/ { sub(/,/, ""); print $1}')
|
||||
fi
|
||||
|
||||
# get the regular commands
|
||||
if [[ -z "$cur" || "$cur" =~ ^[a-z] ]]; then
|
||||
helpopts=$($lncli help 2>/dev/null | awk '$1 ~ /^[a-z]/ { print $1; }' )
|
||||
fi
|
||||
|
||||
completions="$helpopts $globalcmds help"
|
||||
|
||||
# shellcheck disable=SC2207
|
||||
COMPREPLY=( $( compgen -W "$completions" -X "*," -- "$cur" ) )
|
||||
fi
|
||||
} &&
|
||||
complete -F _lncli lnd_coord &&
|
||||
complete -F _lncli lnd_user
|
138
scripts/traditional/templates/strfry.conf
Normal file
138
scripts/traditional/templates/strfry.conf
Normal file
@ -0,0 +1,138 @@
|
||||
##
|
||||
## Default strfry config
|
||||
##
|
||||
|
||||
# Directory that contains the strfry LMDB database (restart required)
|
||||
db = "$STRFRY_DIR/"
|
||||
|
||||
dbParams {
|
||||
# Maximum number of threads/processes that can simultaneously have LMDB transactions open (restart required)
|
||||
maxreaders = 256
|
||||
|
||||
# Size of mmap() to use when loading LMDB (default is 10TB, does *not* correspond to disk-space used) (restart required)
|
||||
mapsize = 10995116277760
|
||||
|
||||
# Disables read-ahead when accessing the LMDB mapping. Reduces IO activity when DB size is larger than RAM. (restart required)
|
||||
noReadAhead = false
|
||||
}
|
||||
|
||||
events {
|
||||
# Maximum size of normalised JSON, in bytes
|
||||
maxEventSize = 65536
|
||||
|
||||
# Events newer than this will be rejected
|
||||
rejectEventsNewerThanSeconds = 900
|
||||
|
||||
# Events older than this will be rejected
|
||||
rejectEventsOlderThanSeconds = 94608000
|
||||
|
||||
# Ephemeral events older than this will be rejected
|
||||
rejectEphemeralEventsOlderThanSeconds = 60
|
||||
|
||||
# Ephemeral events will be deleted from the DB when older than this
|
||||
ephemeralEventsLifetimeSeconds = 300
|
||||
|
||||
# Maximum number of tags allowed
|
||||
maxNumTags = 2000
|
||||
|
||||
# Maximum size for tag values, in bytes
|
||||
maxTagValSize = 1024
|
||||
}
|
||||
|
||||
relay {
|
||||
# Interface to listen on. Use 0.0.0.0 to listen on all interfaces (restart required)
|
||||
bind = "127.0.0.1"
|
||||
|
||||
# Port to open for the nostr websocket protocol (restart required)
|
||||
port = $STRFRY_PORT
|
||||
|
||||
# Set OS-limit on maximum number of open files/sockets (if 0, don't attempt to set) (restart required)
|
||||
nofiles = 1000000
|
||||
|
||||
# HTTP header that contains the client's real IP, before reverse proxying (ie x-real-ip) (MUST be all lower-case)
|
||||
realIpHeader = ""
|
||||
|
||||
info {
|
||||
# NIP-11: Name of this server. Short/descriptive (< 30 characters)
|
||||
name = "Robosats"
|
||||
|
||||
# NIP-11: Detailed information about relay, free-form
|
||||
description = "Federation cache system."
|
||||
|
||||
# NIP-11: Administrative nostr pubkey, for contact purposes
|
||||
pubkey = ""
|
||||
|
||||
# NIP-11: Alternative administrative contact (email, website, etc)
|
||||
contact = ""
|
||||
}
|
||||
|
||||
# Maximum accepted incoming websocket frame size (should be larger than max event) (restart required)
|
||||
maxWebsocketPayloadSize = 131072
|
||||
|
||||
# Websocket-level PING message frequency (should be less than any reverse proxy idle timeouts) (restart required)
|
||||
autoPingSeconds = 55
|
||||
|
||||
# If TCP keep-alive should be enabled (detect dropped connections to upstream reverse proxy)
|
||||
enableTcpKeepalive = false
|
||||
|
||||
# How much uninterrupted CPU time a REQ query should get during its DB scan
|
||||
queryTimesliceBudgetMicroseconds = 10000
|
||||
|
||||
# Maximum records that can be returned per filter
|
||||
maxFilterLimit = 500
|
||||
|
||||
# Maximum number of subscriptions (concurrent REQs) a connection can have open at any time
|
||||
maxSubsPerConnection = 3
|
||||
|
||||
writePolicy {
|
||||
# If non-empty, path to an executable script that implements the writePolicy plugin logic
|
||||
plugin = ""
|
||||
}
|
||||
|
||||
compression {
|
||||
# Use permessage-deflate compression if supported by client. Reduces bandwidth, but slight increase in CPU (restart required)
|
||||
enabled = true
|
||||
|
||||
# Maintain a sliding window buffer for each connection. Improves compression, but uses more memory (restart required)
|
||||
slidingWindow = false
|
||||
}
|
||||
|
||||
logging {
|
||||
# Dump all incoming messages
|
||||
dumpInAll = false
|
||||
|
||||
# Dump all incoming EVENT messages
|
||||
dumpInEvents = false
|
||||
|
||||
# Dump all incoming REQ/CLOSE messages
|
||||
dumpInReqs = false
|
||||
|
||||
# Log performance metrics for initial REQ database scans
|
||||
dbScanPerf = false
|
||||
|
||||
# Log reason for invalid event rejection? Can be disabled to silence excessive logging
|
||||
invalidEvents = true
|
||||
}
|
||||
|
||||
numThreads {
|
||||
# Ingester threads: route incoming requests, validate events/sigs (restart required)
|
||||
ingester = 3
|
||||
|
||||
# reqWorker threads: Handle initial DB scan for events (restart required)
|
||||
reqWorker = 3
|
||||
|
||||
# reqMonitor threads: Handle filtering of new events (restart required)
|
||||
reqMonitor = 3
|
||||
|
||||
# negentropy threads: Handle negentropy protocol messages (restart required)
|
||||
negentropy = 2
|
||||
}
|
||||
|
||||
negentropy {
|
||||
# Support negentropy protocol messages
|
||||
enabled = true
|
||||
|
||||
# Maximum records that sync will process before returning an error
|
||||
maxSyncEvents = 1000000
|
||||
}
|
||||
}
|
468
scripts/traditional/traditional-services
Executable file
468
scripts/traditional/traditional-services
Executable file
@ -0,0 +1,468 @@
|
||||
#!/bin/sh
|
||||
|
||||
_command_exist() {
|
||||
if command -v "$1" >/dev/null 2>&1; then
|
||||
return 0
|
||||
else
|
||||
echo "error: $1 command not found" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
_create_dir() {
|
||||
if [ ! -e "$1" ]; then
|
||||
mkdir -p "$1" || return "$?"
|
||||
if [ "$#" -ge 2 ]; then
|
||||
if ! chmod "$2" "$1"; then
|
||||
echo "error: setting chmod $2 of $1" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
elif [ ! -d "$1" ]; then
|
||||
echo "error: $1 is not a directory" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# if $2 is provided use it as default
|
||||
# otherwise return error when not found
|
||||
_get_env_var() {
|
||||
if ! env_var="$(dotenv -f ".env" get "$1" 2>/dev/null)"; then
|
||||
if [ "$#" -ge 2 ]; then
|
||||
env_var="$2"
|
||||
else
|
||||
echo "error: getting $1 from .env" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
printf "%s\n" "$env_var"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# transform relative path into absolute and remove trailing slashes
|
||||
_get_env_var_path() {
|
||||
env_var="$(_get_env_var "$@")" || return "$?"
|
||||
real_path="$(realpath -m "$env_var")" || return "$?"
|
||||
printf "%s\n" "$real_path"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_services_environment_set() {
|
||||
TRADITIONAL_SERVICES_DIR="$(_get_env_var_path "TRADITIONAL_SERVICES_DIR")" || return "$?"
|
||||
TRADITIONAL_LOGS_DIR="$(_get_env_var_path "TRADITIONAL_LOGS_DIR")" || return "$?"
|
||||
_create_dir "$TRADITIONAL_SERVICES_DIR" || return "$?"
|
||||
_create_dir "$TRADITIONAL_LOGS_DIR" || return "$?"
|
||||
|
||||
POSTGRES_DIR="$TRADITIONAL_SERVICES_DIR/postgres"
|
||||
REDIS_DIR="$TRADITIONAL_SERVICES_DIR/redis"
|
||||
STRFRY_DIR="$TRADITIONAL_SERVICES_DIR/strfry"
|
||||
GNUPG_DIR="$(_get_env_var_path "GNUPG_DIR")" || return "$?"
|
||||
|
||||
POSTGRES_DB="$(_get_env_var "POSTGRES_DB")" || return "$?"
|
||||
POSTGRES_USER="$(_get_env_var "POSTGRES_USER")" || return "$?"
|
||||
POSTGRES_PASS="$(_get_env_var "POSTGRES_PASSWORD")" || return "$?"
|
||||
POSTGRES_PORT="$(_get_env_var "POSTGRES_PORT")" || return "$?"
|
||||
|
||||
REDIS_URL="$(_get_env_var "REDIS_URL")" || return "$?"
|
||||
REDIS_PORT="$(
|
||||
printf "%s\n" "$REDIS_URL" |
|
||||
rev |
|
||||
cut -d ":" -f 1 |
|
||||
rev |
|
||||
cut -d "/" -f 1
|
||||
)"
|
||||
|
||||
STRFRY_GIT_DIR="$(_get_env_var_path "STRFRY_GIT_DIR")" || return "$?"
|
||||
|
||||
RUNSERVER_PORT="$(_get_env_var "RUNSERVER_PORT")" || return "$?"
|
||||
STRFRY_PORT="$(_get_env_var "STRFRY_PORT")" || return "$?"
|
||||
|
||||
if [ "$POSTGRES_DB" = "postgres" ]; then
|
||||
echo "error: POSTGRES_DB should not be postgres" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ "$POSTGRES_USER" = "$USER" ]; then
|
||||
echo "error: POSTGRES_USER should not be the same as USER" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
TRADITIONAL_DIR="$(realpath "$(dirname "$0")")"
|
||||
|
||||
STRFRY_CONF="$STRFRY_DIR/strfry.conf"
|
||||
|
||||
strfry_bin="$STRFRY_GIT_DIR/strfry"
|
||||
|
||||
# to prevent having same command names and killing wrong programs
|
||||
python_bin="$(which python3)"
|
||||
celery_bin="$(which celery)"
|
||||
|
||||
# docker-compose.yml
|
||||
|
||||
RUNSERVER_COMMAND="$python_bin manage.py runserver 0.0.0.0:$RUNSERVER_PORT"
|
||||
|
||||
CLEAN_ORDERS_COMMAND="$python_bin manage.py clean_orders"
|
||||
FOLLOW_INVOICES_COMMAND="$python_bin manage.py follow_invoices"
|
||||
# TELEGRAM_WATCHER_COMMAND="$python_bin manage.py telegram_watcher"
|
||||
|
||||
CELERY_DEV_COMMAND="$celery_bin -A robosats worker --loglevel=INFO --concurrency 4 --max-tasks-per-child=4 --max-memory-per-child=200000"
|
||||
CELERY_BEAT_COMMAND="$celery_bin -A robosats beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler"
|
||||
|
||||
STRFRY_RELAY_COMMAND="$strfry_bin --config $STRFRY_CONF relay"
|
||||
}
|
||||
|
||||
strfry_setup() {
|
||||
if [ -e "$STRFRY_CONF" ]; then
|
||||
echo "strfry conf $STRFRY_CONF already exists"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_create_dir "$STRFRY_DIR" "0700" || return "$?"
|
||||
|
||||
cp "$TRADITIONAL_DIR/templates/strfry.conf" "$STRFRY_CONF"
|
||||
|
||||
sed -i "s|\$STRFRY_DIR|$STRFRY_DIR|g" "$STRFRY_CONF"
|
||||
sed -i "s/\$STRFRY_PORT/$STRFRY_PORT/g" "$STRFRY_CONF"
|
||||
|
||||
echo "strfry directory set up"
|
||||
}
|
||||
|
||||
postgres_action() {
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "error: insert postgres action" >&2
|
||||
return 1
|
||||
fi
|
||||
action="$1"
|
||||
shift 1
|
||||
case "$action" in
|
||||
setup|database) ;;
|
||||
*)
|
||||
echo "error: wrong action" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if ! _command_exist postgres; then
|
||||
return 1
|
||||
fi
|
||||
if ! _command_exist initdb; then
|
||||
return 1
|
||||
fi
|
||||
if ! _command_exist psql; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "$action" in
|
||||
setup)
|
||||
if [ -e "$POSTGRES_DIR" ]; then
|
||||
echo "postgres directory $POSTGRES_DIR already exists"
|
||||
return 0
|
||||
fi
|
||||
_create_dir "$POSTGRES_DIR" "0700" || return "$?"
|
||||
|
||||
if ! initdb -D "$POSTGRES_DIR"; then
|
||||
echo "error: running initdb" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
cat << EOF > "$POSTGRES_DIR/postgresql.conf"
|
||||
port = $POSTGRES_PORT
|
||||
unix_socket_directories = '$POSTGRES_DIR'
|
||||
EOF
|
||||
;;
|
||||
database)
|
||||
if [ ! -d "$POSTGRES_DIR" ]; then
|
||||
printf "%s%s\n" \
|
||||
"error: $POSTGRES_DIR is not a directory, " \
|
||||
"should run postgres-setup" \
|
||||
>&2
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
postgres_setup_log_file="$TRADITIONAL_LOGS_DIR/postgres-setup-log"
|
||||
echo "starting postgres, setup log file is $postgres_setup_log_file"
|
||||
postgres -D "$POSTGRES_DIR" >>"$postgres_setup_log_file" 2>&1 &
|
||||
postgres_pid="$!"
|
||||
|
||||
_postgres_shut_down() {
|
||||
echo "shutting down postgres"
|
||||
if ! kill "$postgres_pid"; then
|
||||
echo "error: shutting down postgres" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
echo "wait..."
|
||||
sleep 5
|
||||
|
||||
case "$action" in
|
||||
setup)
|
||||
echo "setting up postgres user $POSTGRES_USER"
|
||||
psql_stdin=$(cat << EOF
|
||||
CREATE ROLE $POSTGRES_USER WITH LOGIN PASSWORD '$POSTGRES_PASS';
|
||||
ALTER ROLE $POSTGRES_USER CREATEDB;
|
||||
EOF
|
||||
)
|
||||
;;
|
||||
database)
|
||||
psql_stdin=$(cat << EOF
|
||||
CREATE DATABASE $POSTGRES_DB OWNER $POSTGRES_USER;
|
||||
EOF
|
||||
)
|
||||
;;
|
||||
esac
|
||||
printf "%s\n" "$psql_stdin" |
|
||||
psql -h localhost -p "$POSTGRES_PORT" -U "$USER" -d postgres
|
||||
|
||||
echo "wait..."
|
||||
sleep 5
|
||||
|
||||
case "$action" in
|
||||
database)
|
||||
if ! DJANGO_SUPERUSER_USERNAME="$(_get_env_var "ESCROW_USERNAME")"; then
|
||||
_postgres_shut_down || return "$?"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! python3 manage.py migrate; then
|
||||
_postgres_shut_down || return "$?"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
DJANGO_SUPERUSER_PASSWORD="password"
|
||||
DJANGO_SUPERUSER_EMAIL="superuser@email.com"
|
||||
if ! python3 manage.py createsuperuser \
|
||||
--noinput \
|
||||
--username "$DJANGO_SUPERUSER_USERNAME" \
|
||||
--email "$DJANGO_SUPERUSER_EMAIL"
|
||||
then
|
||||
_postgres_shut_down || return "$?"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
_postgres_shut_down || return "$?"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
cleanup_signal() {
|
||||
printf "\n"
|
||||
printf "%s\n" "Caught $1 signal, sending it to services..."
|
||||
|
||||
pkill -"$2" -f "$STRFRY_RELAY_COMMAND"
|
||||
pkill -"$2" -f "$CELERY_BEAT_COMMAND"
|
||||
pkill -"$2" -f "$CELERY_DEV_COMMAND"
|
||||
pkill -"$2" -f "$FOLLOW_INVOICES_COMMAND"
|
||||
# pkill -"$2" -f "$TELEGRAM_WATCHER_COMMAND"
|
||||
pkill -"$2" -f "$CLEAN_ORDERS_COMMAND"
|
||||
pkill -"$2" -f "$RUNSERVER_COMMAND"
|
||||
pkill -"$2" -f "redis-server \*:${REDIS_PORT}"
|
||||
pkill -"$2" -f "postgres -D $POSTGRES_DIR"
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
cleanup_int() {
|
||||
printf "\n"
|
||||
printf "%s\n" "Caught INT signal, shutting down services..."
|
||||
|
||||
pkill -TERM -f "$STRFRY_RELAY_COMMAND"
|
||||
pkill -INT -f "$CELERY_BEAT_COMMAND"
|
||||
pkill -INT -f "$CELERY_DEV_COMMAND"
|
||||
pkill -TERM -f "$FOLLOW_INVOICES_COMMAND"
|
||||
# pkill -TERM -f "$TELEGRAM_WATCHER_COMMAND"
|
||||
pkill -TERM -f "$CLEAN_ORDERS_COMMAND"
|
||||
pkill -TERM -f "$RUNSERVER_COMMAND"
|
||||
pkill -INT -f "redis-server \*:${REDIS_PORT}"
|
||||
pkill -INT -f "postgres -D $POSTGRES_DIR"
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
main_loop() {
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "error: insert main loop action" >&2
|
||||
return 1
|
||||
fi
|
||||
action="$1"
|
||||
shift 1
|
||||
case "$action" in
|
||||
test|server) ;;
|
||||
*)
|
||||
echo "error: $1 is invalid" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if ! _command_exist postgres; then
|
||||
return 1
|
||||
fi
|
||||
if ! _command_exist redis-server; then
|
||||
return 1
|
||||
fi
|
||||
if [ "$action" = "server" ]; then
|
||||
if ! _command_exist celery; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -d "$POSTGRES_DIR" ]; then
|
||||
printf "%s%s\n" \
|
||||
"error: $POSTGRES_DIR is not a directory, " \
|
||||
"should run postgres-setup and postgres-database" \
|
||||
>&2
|
||||
return 1
|
||||
fi
|
||||
if [ "$action" = "server" ]; then
|
||||
if [ ! -d "$STRFRY_DIR" ]; then
|
||||
printf "%s%s\n" \
|
||||
"error: $STRFRY_DIR is not a directory, " \
|
||||
"should run setup" \
|
||||
>&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! pgrep -a bitcoind >/dev/null 2>&1 || {
|
||||
! pgrep -a lightningd >/dev/null 2>&1 &&
|
||||
! pgrep -a lnd >/dev/null 2>&1
|
||||
}; then
|
||||
printf "%s%s\n" \
|
||||
"error: bitcoin or lightning not running, " \
|
||||
"make sure to run this script after running regtest-nodes" \
|
||||
>&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
_create_dir "$REDIS_DIR" || return "$?"
|
||||
_create_dir "$GNUPG_DIR" "0700" || return "$?"
|
||||
|
||||
trap "cleanup_signal HUP" HUP
|
||||
trap "cleanup_signal QUIT" QUIT
|
||||
trap "cleanup_signal TERM" TERM
|
||||
trap "cleanup_int" INT
|
||||
|
||||
while true; do
|
||||
if ! pgrep -f "postgres -D $POSTGRES_DIR" >/dev/null; then
|
||||
echo "starting postgres"
|
||||
postgres -D "$POSTGRES_DIR" >> "$TRADITIONAL_LOGS_DIR/postgres" 2>&1 &
|
||||
fi
|
||||
|
||||
if ! pgrep -f "redis-server \*:${REDIS_PORT}" >/dev/null; then
|
||||
echo "starting redis"
|
||||
printf "%s\n%s\n%s\n" \
|
||||
"dir $REDIS_DIR" \
|
||||
"port $REDIS_PORT" \
|
||||
"maxclients 1024" |
|
||||
redis-server - >> "$TRADITIONAL_LOGS_DIR/redis" 2>&1 &
|
||||
fi
|
||||
|
||||
if [ "$action" = "server" ]; then
|
||||
if ! pgrep -f "$RUNSERVER_COMMAND" >/dev/null; then
|
||||
echo "starting runserver"
|
||||
$RUNSERVER_COMMAND \
|
||||
>> "$TRADITIONAL_LOGS_DIR/runserver" 2>&1 &
|
||||
fi
|
||||
|
||||
if ! pgrep -f "$STRFRY_RELAY_COMMAND" >/dev/null; then
|
||||
echo "starting strfry relay"
|
||||
$STRFRY_RELAY_COMMAND \
|
||||
>> "$TRADITIONAL_LOGS_DIR/strfry-relay" 2>&1 &
|
||||
fi
|
||||
|
||||
if ! pgrep -f "$CLEAN_ORDERS_COMMAND" >/dev/null; then
|
||||
echo "starting clean-orders"
|
||||
$CLEAN_ORDERS_COMMAND \
|
||||
>> "$TRADITIONAL_LOGS_DIR/clean-orders" 2>&1 &
|
||||
fi
|
||||
|
||||
if ! pgrep -f "$FOLLOW_INVOICES_COMMAND" >/dev/null; then
|
||||
echo "starting follow-invoices"
|
||||
$FOLLOW_INVOICES_COMMAND \
|
||||
>> "$TRADITIONAL_LOGS_DIR/follow-invoices" 2>&1 &
|
||||
fi
|
||||
|
||||
# if _get_env_var "TELEGRAM_TOKEN" >/dev/null 2>&1; then
|
||||
# if ! pgrep -f "$TELEGRAM_WATCHER_COMMAND" >/dev/null; then
|
||||
# echo "starting telegram-watcher"
|
||||
# $TELEGRAM_WATCHER_COMMAND \
|
||||
# >> "$TRADITIONAL_LOGS_DIR/telegram-watcher" 2>&1 &
|
||||
# fi
|
||||
# fi
|
||||
|
||||
if ! pgrep -f "$CELERY_DEV_COMMAND" >/dev/null; then
|
||||
echo "starting celery worker"
|
||||
$CELERY_DEV_COMMAND >> "$TRADITIONAL_LOGS_DIR/celery-worker" 2>&1 &
|
||||
fi
|
||||
|
||||
if ! pgrep -f "$CELERY_BEAT_COMMAND" >/dev/null; then
|
||||
echo "starting celery beat"
|
||||
$CELERY_BEAT_COMMAND >> "$TRADITIONAL_LOGS_DIR/celery-beat" 2>&1 &
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
done
|
||||
}
|
||||
|
||||
_services_main() {
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "error: insert action" >&2
|
||||
return 1
|
||||
fi
|
||||
action="$1"
|
||||
shift 1
|
||||
|
||||
if [ ! -f ".env" ]; then
|
||||
echo "error: .env is not present" >&2
|
||||
return 1
|
||||
fi
|
||||
if ! _command_exist dotenv; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "$action" in
|
||||
-h|--help)
|
||||
cat << EOF
|
||||
traditional-services action
|
||||
|
||||
postgres-setup
|
||||
postgres-database
|
||||
strfry-setup
|
||||
nginx-setup
|
||||
test
|
||||
server
|
||||
EOF
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
_services_environment_set || return "$?"
|
||||
|
||||
case "$action" in
|
||||
postgres-setup)
|
||||
postgres_action "setup"
|
||||
;;
|
||||
postgres-database)
|
||||
postgres_action "database"
|
||||
;;
|
||||
strfry-setup)
|
||||
strfry_setup
|
||||
;;
|
||||
test|server)
|
||||
main_loop "$action"
|
||||
;;
|
||||
*)
|
||||
echo "error: action $action not recognized" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_services_main "$@"
|
6
setup.md
6
setup.md
@ -103,3 +103,9 @@ You will need these commands also often or eventually:
|
||||
`docker exec -it lnd-dev lncli -network=testnet payinvoice <BOLT_11_INVOICE> --allow_self_payment`
|
||||
|
||||
**RoboSats development site should be accessible on 127.0.0.1:8000**
|
||||
|
||||
# Backend Development
|
||||
|
||||
## Traditional environment without docker
|
||||
|
||||
See [scripts/traditional/README.md](scripts/traditional/README.md)
|
||||
|
@ -1,7 +1,12 @@
|
||||
import unittest
|
||||
from decouple import config
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
SKIP_FRONTEND_TESTS = config('SKIP_FRONTEND_TESTS', default=False, cast=bool)
|
||||
|
||||
@unittest.skipIf(SKIP_FRONTEND_TESTS, "Skipping frontend tests")
|
||||
class FrontendFetchTest(TestCase):
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
|
@ -16,17 +16,24 @@ def get_node(name="robot"):
|
||||
We have two regtest LND nodes: "coordinator" (the robosats backend) and "robot" (the robosats user)
|
||||
"""
|
||||
if name == "robot":
|
||||
macaroon = codecs.encode(
|
||||
open("/lndrobot/data/chain/bitcoin/regtest/admin.macaroon", "rb").read(),
|
||||
"hex",
|
||||
admin_macaroon_file = config(
|
||||
"LND_TEST_USER_MACAROON_PATH", cast=str,
|
||||
default="/lndrobot/data/chain/bitcoin/regtest/admin.macaroon"
|
||||
)
|
||||
port = 8080
|
||||
macaroon = codecs.encode(
|
||||
open(admin_macaroon_file, "rb").read(), "hex",
|
||||
)
|
||||
port = config("LND_TEST_USER_REST_PORT", cast=int, default=8080)
|
||||
|
||||
elif name == "coordinator":
|
||||
macaroon = codecs.encode(
|
||||
open("/lnd/data/chain/bitcoin/regtest/admin.macaroon", "rb").read(), "hex"
|
||||
admin_macaroon_file = config(
|
||||
"LND_TEST_COORD_MACAROON_PATH", cast=str,
|
||||
default="/lnd/data/chain/bitcoin/regtest/admin.macaroon"
|
||||
)
|
||||
port = 8081
|
||||
macaroon = codecs.encode(
|
||||
open(admin_macaroon_file, "rb").read(), "hex"
|
||||
)
|
||||
port = config("LND_TEST_COORD_REST_PORT", cast=int, default=8081)
|
||||
|
||||
return {"port": port, "headers": {"Grpc-Metadata-macaroon": macaroon}}
|
||||
|
||||
@ -158,10 +165,10 @@ def set_up_regtest_network():
|
||||
# Coordinator is either LND or CLN. Robot user is always LND.
|
||||
if LNVENDOR == "LND":
|
||||
coordinator_node_id = get_lnd_node_id("coordinator")
|
||||
coordinator_port = 9735
|
||||
coordinator_port = config("LND_TEST_COORD_LISTEN_PORT", cast=int, default=9735)
|
||||
elif LNVENDOR == "CLN":
|
||||
coordinator_node_id = get_cln_node_id()
|
||||
coordinator_port = 9737
|
||||
coordinator_port = config("CLN_TEST_COORD_LISTEN_PORT", cast=int, default=9737)
|
||||
|
||||
print("Coordinator Node ID: ", coordinator_node_id)
|
||||
|
||||
@ -258,8 +265,12 @@ def generate_blocks(address, num_blocks):
|
||||
"method": "generatetoaddress",
|
||||
"params": [num_blocks, address],
|
||||
}
|
||||
# set in docker-tests.yml
|
||||
rpc_url = config("BITCOIND_RPCURL", cast=str, default="http://localhost:18443")
|
||||
rpc_user = config("BITCOIND_RPCUSER", cast=str, default="test")
|
||||
rpc_pass = config("BITCOIND_RPCPASSWORD", cast=str, default="test")
|
||||
response = requests.post(
|
||||
"http://localhost:18443", json=data, auth=HTTPBasicAuth("test", "test")
|
||||
rpc_url, json=data, auth=HTTPBasicAuth(rpc_user, rpc_pass)
|
||||
)
|
||||
return response.json()
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
from decouple import config
|
||||
import gnupg
|
||||
|
||||
|
||||
def sign_message(message, private_key_path, passphrase_path):
|
||||
gpg = gnupg.GPG()
|
||||
gpg = gnupg.GPG(gnupghome=config("GNUPG_DIR", default=None))
|
||||
|
||||
with open(private_key_path, "r") as f:
|
||||
private_key = f.read()
|
||||
|
Reference in New Issue
Block a user