Compare commits
3 Commits
5754104fb8
...
reset
| Author | SHA1 | Date | |
|---|---|---|---|
| b759fc1954 | |||
| e15826b645 | |||
| 84df4b7cb8 |
94
README.md
94
README.md
@@ -49,82 +49,108 @@ The easiest way to run Pallectrum is to download the pre-built binaries:
|
||||
|
||||
### Running from Source
|
||||
|
||||
If you want to run Pallectrum from source, you'll need Python 3.10 or higher.
|
||||
Running from source requires **Python 3.10 or higher**. Follow the steps for your platform below.
|
||||
|
||||
---
|
||||
|
||||
#### Windows
|
||||
|
||||
**Prerequisites:**
|
||||
|
||||
- Python 3.10+ installed from [python.org](https://www.python.org/downloads/)
|
||||
|
||||
**Setup with Virtual Environment:**
|
||||
**Prerequisite:** Python 3.10+ from [python.org](https://www.python.org/downloads/)
|
||||
|
||||
```powershell
|
||||
# Clone repository
|
||||
# Clone the repository
|
||||
git clone https://github.com/palladium-coin/pallectrum.git
|
||||
cd pallectrum
|
||||
|
||||
# Create and activate virtual environment
|
||||
# Create and activate a virtual environment
|
||||
python -m venv env
|
||||
env\Scripts\Activate.ps1
|
||||
|
||||
# Upgrade pip and install dependencies
|
||||
# Install dependencies
|
||||
python -m pip install --upgrade pip
|
||||
pip install -e ".[gui,crypto]"
|
||||
|
||||
# Copy libsecp256k1 DLL (if needed)
|
||||
# Copy the secp256k1 library (required on Windows)
|
||||
copy libsecp256k1*.dll env\Lib\site-packages\electrum_ecc\
|
||||
|
||||
# Run with Qt GUI
|
||||
# Launch
|
||||
python run_electrum
|
||||
```
|
||||
|
||||
##### Optional: QML GUI on Windows (simulates Android interface)
|
||||
> **Optional – QML GUI** (simulates the Android interface):
|
||||
> ```powershell
|
||||
> pip install -e ".[qml_gui]"
|
||||
> python run_electrum -g qml
|
||||
> ```
|
||||
|
||||
```powershell
|
||||
pip install ".[qml_gui]"
|
||||
python run_electrum gui -g qml
|
||||
```
|
||||
---
|
||||
|
||||
#### Linux (Ubuntu/Debian)
|
||||
#### Linux (Ubuntu / Debian)
|
||||
|
||||
**Install Prerequisites:**
|
||||
##### 1. Install system prerequisites
|
||||
|
||||
```bash
|
||||
# System packages
|
||||
sudo apt update
|
||||
sudo apt install -y python3-venv python3-pip build-essential python3-dev
|
||||
sudo apt install -y libffi-dev libssl-dev libsecp256k1-dev
|
||||
sudo apt install -y \
|
||||
python3-venv python3-pip python3-dev build-essential \
|
||||
libffi-dev libssl-dev libsecp256k1-dev libpulse0
|
||||
```
|
||||
|
||||
**Setup with Virtual Environment:**
|
||||
##### 2. Clone the repository and set up the virtual environment
|
||||
|
||||
```bash
|
||||
# Clone repository
|
||||
git clone https://github.com/palladium-coin/pallectrum.git
|
||||
cd pallectrum
|
||||
|
||||
# Create and activate virtual environment
|
||||
python3 -m venv env
|
||||
source env/bin/activate
|
||||
|
||||
# Upgrade pip and install dependencies
|
||||
python3 -m pip install --upgrade pip
|
||||
pip install -e ".[gui,crypto]"
|
||||
```
|
||||
|
||||
# Run with Qt GUI
|
||||
##### 3. Install dependencies
|
||||
|
||||
###### 3.1. x86_64 (Intel / AMD)
|
||||
|
||||
```bash
|
||||
pip install -e ".[gui,crypto]"
|
||||
```
|
||||
|
||||
###### 3.2. ARM64 / aarch64
|
||||
|
||||
> PyQt6 ≥ 6.9 wheels are not published for ARM64 on PyPI — pinned versions must be used.
|
||||
|
||||
```bash
|
||||
pip install -r contrib/requirements/requirements.txt
|
||||
pip install "cryptography>=2.6"
|
||||
pip install --only-binary PyQt6,PyQt6-Qt6,PyQt6-sip \
|
||||
"PyQt6>=6.7.0,<6.8.0" \
|
||||
"PyQt6-Qt6>=6.7.0,<6.8.0" \
|
||||
"PyQt6-sip==13.10.2"
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
##### 4. Launch
|
||||
|
||||
```bash
|
||||
python run_electrum
|
||||
```
|
||||
|
||||
##### Optional: QML GUI on Linux (simulates Android interface)
|
||||
###### 4.1. Optional – QML GUI (Android-like interface)
|
||||
|
||||
*x86_64*
|
||||
```bash
|
||||
pip install ".[qml_gui]"
|
||||
python run_electrum gui -g qml
|
||||
pip install -e ".[qml_gui]"
|
||||
python run_electrum -g qml
|
||||
```
|
||||
|
||||
For detailed installation instructions, including dependencies and platform-specific notes, see the [original Electrum documentation](README-ELECTRUM.md#getting-started).
|
||||
*ARM64* — the pinned PyQt6 packages installed in step 3 already include QML support:
|
||||
```bash
|
||||
python run_electrum -g qml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
For the full list of dependencies and advanced configuration options, see [README-ELECTRUM.md#getting-started](README-ELECTRUM.md#getting-started).
|
||||
|
||||
## User Guide
|
||||
|
||||
@@ -168,10 +194,10 @@ Pallectrum stores wallet data and configuration in:
|
||||
|
||||
Pallectrum includes specific adaptations for the Palladium blockchain:
|
||||
|
||||
- BIP21 URI scheme: `palladium:` (instead of `bitcoin:`)
|
||||
- BIP21 URI scheme: `palladium:`
|
||||
- BIP44 coin type: 746
|
||||
- Default block explorer: https://explorer.palladium-coin.com/
|
||||
- Currency unit: PLM (Palladium) instead of BTC
|
||||
- Currency unit: PLM (Palladium)
|
||||
- Checkpoint-based validation (compatible with LWMA difficulty algorithm)
|
||||
|
||||
|
||||
|
||||
@@ -296,6 +296,7 @@ Pane {
|
||||
dialog.open()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,9 +50,73 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Server")
|
||||
enabled: address_tf.enabled
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Label {
|
||||
text: qsTr("Server")
|
||||
enabled: address_tf.enabled
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
icon.source: '../../../icons/delete.png'
|
||||
ToolTip.text: qsTr('Reset network data')
|
||||
ToolTip.visible: hovered
|
||||
onClicked: resetMenu.open()
|
||||
|
||||
Menu {
|
||||
id: resetMenu
|
||||
|
||||
MenuItem {
|
||||
text: qsTr('SSL certificates')
|
||||
onTriggered: {
|
||||
var dialog = app.messageDialog.createObject(app, {
|
||||
title: qsTr('Are you sure?'),
|
||||
text: qsTr('This will remove cached SSL certificates for servers and reconnect to fetch them again.'),
|
||||
yesno: true
|
||||
})
|
||||
dialog.accepted.connect(function() {
|
||||
var removed = Network.clearPinnedServerCertificates()
|
||||
var msg = removed < 0
|
||||
? qsTr('Failed to reset SSL certificates.')
|
||||
: removed > 0
|
||||
? qsTr('%1 certificate files were removed.').arg(removed)
|
||||
: qsTr('No cached certificate files were found.')
|
||||
app.messageDialog.createObject(app, {
|
||||
title: qsTr('Reset SSL certificates'),
|
||||
text: msg
|
||||
}).open()
|
||||
})
|
||||
dialog.open()
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: qsTr('Known servers')
|
||||
onTriggered: {
|
||||
var dialog = app.messageDialog.createObject(app, {
|
||||
title: qsTr('Are you sure?'),
|
||||
text: qsTr('This will remove the list of known servers.'),
|
||||
yesno: true
|
||||
})
|
||||
dialog.accepted.connect(function() {
|
||||
var removed = Network.clearRecentServers()
|
||||
var msg = removed < 0
|
||||
? qsTr('Failed to reset known servers.')
|
||||
: removed > 0
|
||||
? qsTr('%1 server(s) were removed.').arg(removed)
|
||||
: qsTr('No known servers were found.')
|
||||
app.messageDialog.createObject(app, {
|
||||
title: qsTr('Reset known servers'),
|
||||
text: msg
|
||||
}).open()
|
||||
})
|
||||
dialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextHighlightPane {
|
||||
|
||||
@@ -306,3 +306,19 @@ class QENetwork(QObject, QtEventListener):
|
||||
@pyqtSlot()
|
||||
def probeTor(self):
|
||||
ProxySettings.probe_tor(self.torProbeFinished.emit) # via signal
|
||||
|
||||
@pyqtSlot(result=int)
|
||||
def clearPinnedServerCertificates(self):
|
||||
try:
|
||||
return self.network.run_from_another_thread(self.network.clear_pinned_server_certs())
|
||||
except Exception:
|
||||
self._logger.exception("failed to clear pinned server certificates")
|
||||
return -1
|
||||
|
||||
@pyqtSlot(result=int)
|
||||
def clearRecentServers(self):
|
||||
try:
|
||||
return self.network.clear_recent_servers()
|
||||
except Exception:
|
||||
self._logger.exception("failed to clear recent servers")
|
||||
return -1
|
||||
|
||||
@@ -29,7 +29,7 @@ from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt6.QtWidgets import (
|
||||
QTreeWidget, QTreeWidgetItem, QMenu, QGridLayout, QComboBox, QLineEdit, QDialog, QVBoxLayout, QHeaderView,
|
||||
QCheckBox, QTabWidget, QWidget, QLabel, QPushButton, QHBoxLayout,
|
||||
QListWidget, QListWidgetItem,
|
||||
QListWidget, QListWidgetItem, QMessageBox,
|
||||
)
|
||||
from PyQt6.QtGui import QIntValidator
|
||||
|
||||
@@ -444,6 +444,16 @@ class ServerWidget(QWidget, QtEventListener):
|
||||
self.layout().addWidget(self.nodes_list_widget)
|
||||
self.nodes_list_widget.update()
|
||||
|
||||
self.clear_certs_button = QPushButton(_('Reset SSL certificates'))
|
||||
self.clear_certs_button.clicked.connect(self.clear_pinned_server_certs)
|
||||
self.clear_servers_button = QPushButton(_('Reset known servers'))
|
||||
self.clear_servers_button.clicked.connect(self.clear_recent_servers)
|
||||
buttons = QHBoxLayout()
|
||||
buttons.addStretch(1)
|
||||
buttons.addWidget(self.clear_certs_button)
|
||||
buttons.addWidget(self.clear_servers_button)
|
||||
self.layout().addLayout(buttons)
|
||||
|
||||
self.register_callbacks()
|
||||
self.destroyed.connect(lambda: self.unregister_callbacks())
|
||||
|
||||
@@ -584,6 +594,54 @@ class ServerWidget(QWidget, QtEventListener):
|
||||
_logger.debug(f"set_server: {new_net_params=}")
|
||||
self.network.run_from_another_thread(self.network.set_parameters(new_net_params))
|
||||
|
||||
def clear_pinned_server_certs(self):
|
||||
result = QMessageBox.question(
|
||||
self,
|
||||
_('Reset SSL certificates'),
|
||||
_('This will remove cached SSL certificates for servers and reconnect to fetch them again.')
|
||||
+ '\n\n'
|
||||
+ _('Do you want to continue?'),
|
||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||
QMessageBox.StandardButton.No,
|
||||
)
|
||||
if result != QMessageBox.StandardButton.Yes:
|
||||
return
|
||||
try:
|
||||
removed = self.network.run_from_another_thread(self.network.clear_pinned_server_certs())
|
||||
except Exception as e:
|
||||
_logger.exception("failed to clear pinned server certificates")
|
||||
QMessageBox.critical(self, _('Reset SSL certificates'), str(e))
|
||||
return
|
||||
if removed > 0:
|
||||
msg = _('{} certificate files were removed.').format(removed)
|
||||
else:
|
||||
msg = _('No cached certificate files were found.')
|
||||
QMessageBox.information(self, _('Reset SSL certificates'), msg)
|
||||
|
||||
def clear_recent_servers(self):
|
||||
result = QMessageBox.question(
|
||||
self,
|
||||
_('Reset known servers'),
|
||||
_('This will remove the list of known servers.')
|
||||
+ '\n\n'
|
||||
+ _('Do you want to continue?'),
|
||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||
QMessageBox.StandardButton.No,
|
||||
)
|
||||
if result != QMessageBox.StandardButton.Yes:
|
||||
return
|
||||
try:
|
||||
removed = self.network.clear_recent_servers()
|
||||
except Exception as e:
|
||||
_logger.exception("failed to clear recent servers")
|
||||
QMessageBox.critical(self, _('Reset known servers'), str(e))
|
||||
return
|
||||
if removed > 0:
|
||||
msg = _('{} server(s) were removed.').format(removed)
|
||||
else:
|
||||
msg = _('No known servers were found.')
|
||||
QMessageBox.information(self, _('Reset known servers'), msg)
|
||||
|
||||
|
||||
class NostrWidget(QWidget, QtEventListener):
|
||||
|
||||
|
||||
@@ -408,6 +408,36 @@ class Network(Logger, NetworkRetryManager[ServerAddr]):
|
||||
"""Our guess whether the device has Internet-connectivity."""
|
||||
return self._has_ever_managed_to_connect_to_server
|
||||
|
||||
def clear_recent_servers(self) -> int:
|
||||
"""Clear the list of recently used servers."""
|
||||
with self.recent_servers_lock:
|
||||
count = len(self._recent_servers)
|
||||
self._recent_servers = []
|
||||
self._save_recent_servers()
|
||||
self.logger.info(f"cleared {count} recent server(s)")
|
||||
return count
|
||||
|
||||
async def clear_pinned_server_certs(self) -> int:
|
||||
"""Delete cached server SSL certs and reconnect interfaces."""
|
||||
certs_dir = os.path.join(self.config.path, 'certs')
|
||||
util.make_dir(certs_dir)
|
||||
removed = 0
|
||||
for entry in os.scandir(certs_dir):
|
||||
if not entry.is_file():
|
||||
continue
|
||||
try:
|
||||
os.unlink(entry.path)
|
||||
removed += 1
|
||||
except OSError as e:
|
||||
self.logger.warning(f"failed to delete cert file {entry.path!r}: {e!r}")
|
||||
self.logger.info(f"removed {removed} cached server cert(s)")
|
||||
if removed:
|
||||
with self.interfaces_lock:
|
||||
interfaces = list(self.interfaces.values())
|
||||
for iface in interfaces:
|
||||
await self._close_interface(iface)
|
||||
return removed
|
||||
|
||||
def has_channel_db(self):
|
||||
return self.channel_db is not None
|
||||
|
||||
|
||||
6
setup.py
6
setup.py
@@ -45,7 +45,11 @@ extras_require = {
|
||||
'gui': ['pyqt6'],
|
||||
'crypto': ['cryptography>=2.6'],
|
||||
'tests': ['pycryptodomex>=3.7', 'cryptography>=2.6', 'pyaes>=0.1a1'],
|
||||
'qml_gui': ['pyqt6<6.6', 'pyqt6-qt6<6.6']
|
||||
'qml_gui': [
|
||||
'pyqt6>=6.7.0,<6.8.0',
|
||||
'pyqt6-qt6>=6.7.0,<6.8.0',
|
||||
'pyqt6-sip==13.10.2',
|
||||
],
|
||||
}
|
||||
# 'full' extra that tries to grab everything an enduser would need (except for libsecp256k1...)
|
||||
extras_require['full'] = [pkg for sublist in
|
||||
|
||||
Reference in New Issue
Block a user