Hexa's Blog

Setup kaspa stratum bridge for solo mining

16/07/2024 @ Saigon Cryptocurrency Node

I. Clone repo https://github.com/rdugan/kaspa-stratum-bridge

Or copy relase to /opt/kaspa-ks-bridge

$  kaspa_ks_bridge pwd
/opt/kaspa_ks_bridge

$  kaspa_ks_bridge tree
.
├── bridge.log
├── config.yaml
└── ks_bridge

1 directory, 3 files

II. Modify config.yaml

stratum_port: :5555
kaspad_address: localhost:16110
min_share_diff: 8192
pow2_clamp: true
var_diff: true
shares_per_min: 20
var_diff_stats: true
block_wait_time: 500ms
extranonce_size: 2
print_stats: true
log_to_file: true
prom_port: :2114

III. Systemctl service - /etc/systemd/system/kaspa_ks_bridge.service

[Unit]
Description=Kaspa - KS Bridge
Requires=network.target

[Service]
WorkingDirectory=/opt/kaspa_ks_bridge
ExecStart=/opt/kaspa_ks_bridge/ks_bridge
User=nguyenvinhlinh
RemainAfterExit=yes
Restart=on-failure
RestartSec=10
TimeoutStopSec=180

[Install]
WantedBy=multi-user.target

IV. Config ASIC’s Mining Settings

The pool address should be stratum+tcp://192.168.1.XXX:5555 (your local stratum node ip)

ASIC's Mining setting
ASIC's Mining setting

Kaspa Asic - KS5L - API sample to get operational stage

15/07/2024 @ Saigon Mining Rig

Ice River - KS5L
Ice River - KS5L

This post is all about HTTP API to get ASIC operational stage, in particular KS5L. I believe that this API is also for KS0 and other future Ice River’s ASICs This finding is a part of my open source project named Mining Rig Monitor.

This is the HTTP POST example with curl.

$ curl 'http://192.168.1.XXX/user/userpanel' \
  -H 'Accept: application/json, text/javascript, */*; q=0.01' \
  -H 'Accept-Language: en-US,en;q=0.9,vi-VN;q=0.8,vi;q=0.7' \
  -H 'Connection: keep-alive' \
  -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
  -H 'Cookie: language=en; ctime=1' \
  -H 'DNT: 1' \
  -H 'Origin: http://192.168.1.XXX' \
  -H 'Referer: http://192.168.1.XXX/' \
  -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' \
  -H 'X-Requested-With: XMLHttpRequest' \
  --data-raw 'post=4' \
  --insecure

HTTP 200 - Response

{
  "error": 0,
  "data": {
    "model": "none",
    "algo": "none",
    "online": true,
    "firmver1": "BOOT_3_1",
    "firmver2": "image_1.0",
    "softver1": "ICM168_3_2_10_ks5L_miner",
    "softver2": "ICM168_3_2_10_ks5L_bg",
    "firmtype": "Factory",
    "nic": "eth0",
    "mac": "****:****:****:****:****:**",
    "ip": "192.168.1.XX",
    "netmask": "255.255.255.0",
    "host": "XJGXG_SSYYGB",
    "dhcp": false,
    "gateway": "192.168.1.xxfe80::1",
    "dns": "xx.xx.xx.xx",
    "locate": false,
    "rtpow": "15011G",
    "avgpow": "10789G",
    "reject": 0.0,
    "runtime": "01:04:29:02",
    "unit": "G",
    "pows": {
      "board1": [
        10789,
        9851,
        11728,
        11728,
        9851,
        8913,
        7505,
        7505,
        8913,
        8913,
        13135,
        8444,
        10320,
        7036,
        5629,
        12197,
        9382,
        12666,
        11258,
        9382,
        7505,
        8913,
        15011
      ]
    },
    "pows_x": [
      "0 mins",
      "5 mins",
      "10 mins",
      "15 mins",
      "20 mins",
      "25 mins",
      "30 mins",
      "35 mins",
      "40 mins",
      "45 mins",
      "50 mins",
      "55 mins",
      "60 mins",
      "65 mins",
      "70 mins",
      "75 mins",
      "80 mins",
      "85 mins",
      "90 mins",
      "95 mins",
      "100 mins",
      "105 mins",
      "110 mins"
    ],
    "powstate": true,
    "netstate": true,
    "fanstate": true,
    "tempstate": false,
    "fans": [
      5900,
      5900,
      5900,
      5855
    ],
    "pools": [
      {
        "no": 1.0,
        "addr": "stratum+tcp://asia1.kaspa-pool.org:4441",
        "user": "kaspa:qr3d34p6gzewwjs93fvheruwjyvfn35kn5uu00e6ffsgt6k087c4qsgp8l0mk.worker_1",
        "pass": "x",
        "connect": 1.0,
        "diff": "140737.49 G",
        "priority": 1.0,
        "accepted": 7225.0,
        "rejected": 0.0,
        "diffa": 0.0,
        "diffr": 0.0,
        "state": 1.0,
        "lsdiff": 0.0,
        "lstime": "00:00:00"
      },
      {
        "no": 2.0,
        "addr": "stratum+tcp://eu1.kaspa-pool.org:4441",
        "user": "kaspa:**********.worker_1",
        "pass": "x",
        "connect": -1.0,
        "diff": "0.00 G",
        "priority": 2.0,
        "accepted": 0.0,
        "rejected": 0.0,
        "diffa": 0.0,
        "diffr": 0.0,
        "state": 0.0,
        "lsdiff": 0.0,
        "lstime": "00:00:00"
      },
      {
        "no": 3.0,
        "addr": "stratum+tcp://us1.kaspa-pool.org:4441",
        "user": "kaspa:**********.worker_1",
        "pass": "x",
        "connect": -1.0,
        "diff": "0.00 G",
        "priority": 3.0,
        "accepted": 0.0,
        "rejected": 0.0,
        "diffa": 0.0,
        "diffr": 0.0,
        "state": 0.0,
        "lsdiff": 0.0,
        "lstime": "00:00:00"
      }
    ],
    "boards": [
      {
        "no": 1.0,
        "chipnum": 18.0,
        "chipsuc": 0.0,
        "error": 0.0,
        "freq": 875.0,
        "rtpow": "5160.37G",
        "avgpow": "3831.19G",
        "idealpow": "0.00G",
        "tempnum": "(null)",
        "pcbtemp": "0.00-0.00-0.00-0.00",
        "intmp": 61.0,
        "outtmp": 63.0,
        "state": true,
        "false": [
          1,
          2,
          3,
          4,
          5,
          6,
          7,
          8,
          9,
          10,
          11,
          12,
          13,
          14,
          15,
          16,
          17,
          18
        ]
      },
      {
        "no": 2.0,
        "chipnum": 18.0,
        "chipsuc": 0.0,
        "error": 0.0,
        "freq": 875.0,
        "rtpow": "5629.50G",
        "avgpow": "3440.25G",
        "idealpow": "0.00G",
        "tempnum": "(null)",
        "pcbtemp": "0.00-0.00-0.00-0.00",
        "intmp": 57.0,
        "outtmp": 61.0,
        "state": true,
        "false": [
          1,
          2,
          3,
          4,
          5,
          6,
          7,
          8,
          9,
          10,
          11,
          12,
          13,
          14,
          15,
          16,
          17,
          18
        ]
      },
      {
        "no": 3.0,
        "chipnum": 18.0,
        "chipsuc": 0.0,
        "error": 0.0,
        "freq": 875.0,
        "rtpow": "4222.12G",
        "avgpow": "3518.44G",
        "idealpow": "0.00G",
        "tempnum": "(null)",
        "pcbtemp": "0.00-0.00-0.00-0.00",
        "intmp": 62.0,
        "outtmp": 67.0,
        "state": true,
        "false": [
          1,
          2,
          3,
          4,
          5,
          6,
          7,
          8,
          9,
          10,
          11,
          12,
          13,
          14,
          15,
          16,
          17,
          18
        ]
      }
    ],
    "refTime": "2024-03-08 01:58:25 UTC"
  },
  "message": ""
}

I hope that you guys could find it useful, good luck!

Cách làm Certificate Authority cấp SSL nội bộ

15/07/2024 @ Saigon SSL

[1] Mô hình chứng chỉ
[1] Mô hình chứng chỉ

I. Tạo Certificate Authority

a. Tạo private key

$ openssl genrsa -des3 -out my-ca.key 4096

b. Tạo certificate

$ openssl req -x509 -new -nodes -key my-ca.key -sha256 -days 365000 -out my-ca.pem

Kết quả của quá trình này là file my-ca.pem đây là certificate của Certificate Authority. Nói một cách khác, một Certificate Authority đã được tạo.

II. Tạo web1.local certificate

a. Tạo private key

$ openssl genrsa -out web1.local.key 4096

b. Tạo yêu cầu chứng nhận, (Certificate signing request)

$ openssl req -new -key web1.local.key -out web1.local.csr

c. Tạo thêm X509 V3 certificate extension config file

Tạo file có tên là web1.local.ext

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = web1.local

d. Tạo certificate cho web1.local

Yêu cầu:

  • my-ca.key - private key của Certificate Authority(CA)
  • my-ca.pem - certificate của Certificate Authority(CA)
  • web1.local.csr - yêu cầu tạo chứng chỉ(Certificate signing request - CSR) của trang web, ví dụ web1.local
  • web1.local.ext - extension của yêu cầu tạo chứng chỉ.
$ openssl x509 -req -in ./web1.local-cert/web1.local.csr  -CA ./ca-cert/my-ca.pem  -CAkey ./ca-cert/my-ca.key \
    -CAcreateserial -out ./web1.local-cert/web1.local.crt -days 365 -sha256 -extfile  ./web1.local-cert/web1.local.ext

Installing a Kaspa fullnode

I. Systemctl service - /etc/systemd/system/kaspa.service

[Unit]
Description=Kaspa Full Node
After=network.target mnt-disk_2.mount

[Service]
WorkingDirectory=/opt/rusty-kaspa-v0.14.1-linux-gnu-amd64
ExecStart=ExecStart=/opt/rusty-kaspa-v0.14.1-linux-gnu-amd64/bin/kaspad --configfile /opt/rusty-kaspa-v0.14.1-linux-gnu-amd64/bin/kaspad.conf
User=nguyenvinhlinh
RemainAfterExit=yes
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

II. Kaspa config file - /opt/rusty-kaspa-v0.14.1-linux-gnu-amd64/bin/kaspad.conf

appdir="/opt/rusty-kaspa-v0.14.1-linux-gnu-amd64/data"
utxoindex=true
outpeers=128
maxinpeers=128
rpclisten="0.0.0.0:16110"
rpclisten-borsh="0.0.0.0:17110"
listen="0.0.0.0:16111"

II. Firewall-cmd - /etc/firewalld/services/kaspa.xml

<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Kaspa node</short>
  <description>
    This option allows Kaspa node to use tcp port
    - 16110: gRPC for mining + go wallet
    - 16111: P2P
    - 17110: wRPC Borsh for rusty wallet
  </description>
  <port protocol="tcp" port="16110"/>
  <port protocol="tcp" port="16111"/>
  <port protocol="tcp" port="17110"/>
</service>

III. How to use kaspa-wallet?

$ ./kaspa-wallet
####### You are in kaspa-wallet interactive console
$ server 127.0.0.1:17110
Setting RPC server to: 127.0.0.1:17110
$ connect
Connected to Kaspa node version 0.14.1 at ws://127.0.0.1:17110
$ wallet create test_wallet

$ wallet help
unknown command: 'help'

    close             Close an opened wallet (shorthand: 'close')
    create [<name>]   Create a new bip32 wallet
    hint              Change the wallet phishing hint
    import [<name>]   Create a wallet from an existing mnemonic (bip32 only).

                      To import legacy wallets (KDX or kaspanet) please create
                      a new bip32 wallet and use the 'account import' command.
                      Legacy wallets can only be imported as accounts.

    list              List available local wallet files
    open [<name>]     Open an existing wallet (shorthand: 'open [<name>]')

How does this website is built & delploy?

05/07/2024 @ Saigon Projects

1. Introduction

This website is built with Jekyll, build with Docker and deploy with Nginx on bare metal. At the deploy step, it’s all about copy file html files from docker to nginx’s www directory.

A process of auto-build & auto-deploy is done with Jenkins.

2. Jenkins

a. Build Trigger

I use GitHub hook trigger for GITScm polling.

[1] Jenkins - Build Trigger
[1] Jenkins - Build Trigger

In addition, on the github, I configure github’s webhook.

[2] Jenkins - Github's webhook
[2] Jenkins - Github's webhook

b. Pipeline

pipeline {
    agent any

    stages {
        stage('Clone Repo') {
            steps {
                git 'https://github.com/nguyenvinhlinh/nguyenvinhlinh.github.io'
            }
        }

        stage('Build') {
            steps {
                sh 'DOCKER_BUILDKIT=1 docker build -f  Dockerfile --target=release --output nginx-dist .'
            }
        }

        stage('Remove old html') {
            steps {
                sh 'rm -rvf /usr/share/nginx/hexalink.xyz.html/*'
            }
        }

        stage('Copy to /usr/share/nginx/hexalink.xyz.html/') {
            steps {
                sh 'cp -r ./nginx-dist/* /usr/share/nginx/hexalink.xyz.html/'
            }
        }
    }
}

There is a trick here to copy to nginx’s www directory. user named jenkins does copy file htmls into the nginx’s html directory. As a consequence, prior to run pipeline,

  • First, I create nginx’s html directory (/usr/share/nginx/hexalink.xyz.html/)
  • Then, I change user ownership to jenkins.

3. Nginx

a. Nginx config for hexalink.xyz / www.hexalink.xyz

server {
    listen       443 ssl;
    listen       [::]:443 ssl;
    http2        on;
    server_name  hexalink.xyz www.hexalink.xyz;
    root         /usr/share/nginx/abc.xyz.html;

    ssl_certificate "/etc/pki/abc.xyz/www_abc_xyz.bundle.crt";
    ssl_certificate_key "/etc/pki/abc.xyz/www_abc_xyz.pem";
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout  10m;
    ssl_ciphers PROFILE=SYSTEM;
    ssl_prefer_server_ciphers on;
    charset UTF-8;

    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;
}

b. Nginx config for jenkins

I follow this tutorial Reverse proxy - Nginx.

Crypto currency projects & ports collection

05/07/2024 @ Saigon Cryptocurrency Node

This post is all about crypto currency project and it’s default ports. After a while, setup and deploy many project, this is a collection.

Name Port Description NAT port forwarding
Bitcoin 8332 RPC NO
  8333 P2P YES
Monero 18080 P2P YES
  18081 Restricted RPC YES (With Restricted RPC ONLY)
    Full RPC NO
Alephium 9973 P2P YES
  10973 Mining API YES (If mining)
  11973 WebSocket API NO
  12973 JSON API / Swagger NO
Kaspa 16110 gRPC for miner + Go Wallet NO
  16111 P2P YES
  17110 wRPC Borsh for Rusty Wallet Yes if want to allow remote wallet
Spectre 18110 RPC for miner + Go Wallet NO
  18111 P2P YES
  19110 Websocket for Rusty Wallet YES if want to allow remote wallet
Dynex 17333 P2P YES
  17336 P2P YES
Beam 10000 P2P YES

How to build Zephyr wallet GUI in .rpm package, aka Fedora OS?

25/04/2024 @ Saigon Mining Rig

1. Clone source code

Go to https://github.com/ZephyrProtocol/zephyr-wallet and do git clone

$ git clone https://github.com/ZephyrProtocol/zephyr-wallet

2. Build zephyr wallet client

Change directory to zephyr-wallet/client, install packge dependencies and build

$ cd zephyr-wallet
$ cd client
$ npm install
$ export NODE_OPTIONS=--openssl-legacy-provider
$ npm run build:desktop
$ npm run copy-build

3. Build zephyr wallet desktop app

Change directory to zephyr-wallet/zephyr-desktop-app, install package dependencies.

$ cd zephyr-wallet/zephyr-desktop-app
$ npm install

Modify the file named forge.config.js at line 90. Add a new maker named @electron-forge/maker-rpm. This config is a must for Electron Forge to build .rpm file. For reference, please check https://www.electronforge.io/config/makers/rpm.

{
  name: '@electron-forge/maker-rpm',
  config: {
    options: {
      homepage: 'http://example.com'
    }
  }
}

Now, it’s time to build rpm file, I do reference from zephyr-wallet/sh/make.sh

$ cd zephyr-wallet/zephyr-desktop-app
$ export ZEPHYR_DESKTOP_DEVELOPMENT=false
$ export NODE_INSTALLER=npm
$ npm run make -- --targets="@electron-forge/maker-rpm"

> zephyr@1.0.2 make
> npm run build && electron-forge make --targets=@electron-forge/maker-rpm


> zephyr@1.0.2 build
> tsc

✔ Checking your system
✔ Loading configuration
✔ Resolving make targets
  › Making for the following targets: rpm
✔ Running package command
  ✔ Preparing to package application
  ✔ Running packaging hooks
    ✔ Running generateAssets hook
    ✔ Running prePackage hook
  ✔ Packaging application
    ✔ Packaging for x64 on linux [11s]
  ✔ Running postPackage hook
✔ Running preMake hook
✔ Making distributables
  ✔ Making a rpm distributable for linux/x64 [42s]
✔ Running postMake hook
  › Artifacts available at: /home/***/Projects/zephyr-wallet/zephyr-desktop-app/out/make

The rpm file should be in out/make/rpm/x86/. Done!

For quick testing without rpm install, you can execute zephyr-wallet/zephyr-desktop-app/out/Zephyr-linux-x64/zephyr.

For rpm istall, you can run the following command.

$ cd zephyr-desktop-app/out/make/rpm/x64
$ sudo dnf install zephyr-1.0.2-1.x86_64.rpm

4. Screenshots

Zephyr Application Shortcut
Zephyr Application Shortcut
Zephyr Wallet GUI
Zephyr Wallet GUI

Rigel, mining ALPH script

10/10/2023 @ Saigon Mining Rig

Miner Software: Rigel
Version: 1.9.1
Link: https://github.com/rigelminer/rigel
Gear: Nvidia 3080

Keynote:

  • --temp-limit tc[60-65]: Set temperature limit for GPU core to max 65. mining will be back when temperature is 60.
  • --lock-cclock X: Reset GPU core clock, no config, leave it stock config.
  • --lock-mclock 810: Set GPU memory clock to 810Mhz
  • --pl 160: Set power limit to 160W
  • --fan-control 85: Set fan speed to 85%
@echo off
@cd /d "%~dp0"

rigel.exe -a alephium -o stratum+tcp://as.pool.metapool.tech:20032 -u ALPH_ADDRESS_HERE ^
          -w SON_TINH --temp-limit tc[60-65]  --lock-cclock X --lock-mclock 810 --pl 160 --fan-control 85 ^
          --log-file logs/miner.log
pause
Rigel, mining ALPH 3080
Rigel, mining ALPH 3080

How to fix redash saml's self-sign Certificate Authority?

12/09/2023 @ Saigon Redash

During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 600, in urlopen
    chunked=chunked)
  File "/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 343, in _make_request
    self._validate_conn(conn)
  File "/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 839, in _validate_conn
    conn.connect()
  File "/usr/local/lib/python3.7/site-packages/urllib3/connection.py", line 344, in connect
    ssl_context=context)
  File "/usr/local/lib/python3.7/site-packages/urllib3/util/ssl_.py", line 345, in ssl_wrap_socket
    return context.wrap_socket(sock, server_hostname=server_hostname)
  File "/usr/local/lib/python3.7/site-packages/urllib3/contrib/pyopenssl.py", line 462, in wrap_socket
    raise ssl.SSLError('bad handshake: %r' % e)
ssl.SSLError: ("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])",)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/requests/adapters.py", line 449, in send
    timeout=timeout
  File "/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py", line 638, in urlopen
    _stacktrace=sys.exc_info()[2])
  File "/usr/local/lib/python3.7/site-packages/urllib3/util/retry.py", line 399, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host=MY_ADFS_SERVER.LOCAL', port=443):
Max retries exceeded with url: /FederationMetadata/2007-06/FederationMetadata.xml
(Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])")))

Why does it happen?

Redash trying to get SAML’s FederationMetadata.xml from a self-sign ADFS server. Python package named certifi did not update with your new CA’s certificate.

How to solve?

  • Find certifi’s cacert.pem and update it. In terminal, type python to access its interactive shell. Then, type the following command.
>>> import certifi
>>> certifi.where()
'/usr/local/lib/python3.7/site-packages/certifi/cacert.pem'

In this case, it’s /usr/local/lib/python3.7/site-packages/certifi/cacert.pem.

  • Append your CA’s certificate to cacert.pem.
$ cat my-ca.crt >> /usr/local/lib/python3.7/site-packages/certifi/cacert.pem

How to test?

In terminal, type python to access its interactive shell. Then, type the following command.

>>> import requests
>>> requests.request("GET", "https://YOUR_ADFS_DOMAIN/FederationMetadata/2007-06/FederationMetadata.xml")

Good luck!

Reference

How to add Certificate Authority (CA) in Fedora to support chain certificate?

09/09/2023 @ Saigon SSL

Step 1. Using chrome to extract certificates.

[1] Open certificate viewer in Google Chrome
[1] Open certificate viewer in Google Chrome
[2] Export certificate
[2] Export certificate

Only need to use extract CA’s certificate. Export it with file extension named .pem

Please take a note that, update-ca-trust determines certificate format using file header which locates in very first bytes in the binary file. Eventhough you save certificates with .crt , .cer, it’s still .pem.

To determine file format, you shoule use command file, for example $ file file_name.

To illustrate this point. I’ll give an example.

####### List all file, take a look at the file extension, .crt and .pem
$ ls -l
'Default Trust_DigiCert Global Root CA.crt'
'Default Trust_DigiCert Global Root CA.pem'


####### Determine file format with command named `file`
$ file *
Default Trust_DigiCert Global Root CA.crt: PEM certificate
Default Trust_DigiCert Global Root CA.pem: PEM certificate

Step 2. Copy certificate authority’s certificate to /etc/pki/ca-trust/source/anchors

Step 3. Update /etc/ssl/certs/ca-certificates.crt

$ sudo update-ca-trust extract

You can check this file /etc/ssl/certs/ca-certificates.crt to ensure that it is updated.

Step 4. Testing

This is an image before update-ca-trust

[3] Before update-ca-trust
[3] Before update-ca-trust

And, this is an image after update-ca-trust.

[3] After update-ca-trust
[3] After update-ca-trust

Good luck!