Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-depends.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ jobs:
uses: actions/cache/restore@v5
with:
path: depends/sources
key: depends-sources-${{ hashFiles('depends/packages/*') }}
restore-keys: depends-sources-
key: depends-sources-v2-${{ hashFiles('depends/packages/*') }}
restore-keys: depends-sources-v2-

- name: Restore SDKs cache
id: sdk-cache
Expand Down
25 changes: 18 additions & 7 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,7 @@ jobs:
if: |
vars.SKIP_LINUX64 == '' ||
vars.SKIP_LINUX64_ASAN == '' ||
vars.SKIP_LINUX64_FUZZ == '' ||
vars.SKIP_LINUX64_SQLITE == ''
vars.SKIP_LINUX64_FUZZ == ''
with:
build-target: linux64
container-path: ${{ needs.container.outputs.path }}
Expand Down Expand Up @@ -263,6 +262,18 @@ jobs:
runs-on: ${{ needs.check-skip.outputs['runner-amd64'] }}
runs-on-check: ${{ needs.check-skip.outputs['runner-check-skip'] }}

depends-linux64_platform_gui:
name: x86_64-pc-linux-gnu_platform_gui
uses: ./.github/workflows/build-depends.yml
needs: [check-skip, container, cache-sources]
if: ${{ vars.SKIP_LINUX64_SQLITE == '' }}
with:
build-target: linux64_platform_gui
container-path: ${{ needs.container.outputs.path }}
base-image-digest: ${{ needs.check-skip.outputs.base-image-digest }}
runs-on: ${{ needs.check-skip.outputs['runner-amd64'] }}
runs-on-check: ${{ needs.check-skip.outputs['runner-check-skip'] }}

depends-mac:
name: x86_64-apple-darwin
uses: ./.github/workflows/build-depends.yml
Expand Down Expand Up @@ -387,15 +398,15 @@ jobs:
src-linux64_sqlite:
name: linux64_sqlite-build
uses: ./.github/workflows/build-src.yml
needs: [check-skip, container, depends-linux64]
needs: [check-skip, container, depends-linux64_platform_gui]
if: ${{ vars.SKIP_LINUX64_SQLITE == '' }}
with:
build-target: linux64_sqlite
container-path: ${{ needs.container.outputs.path }}
depends-key: ${{ needs.depends-linux64.outputs.key }}
depends-host: ${{ needs.depends-linux64.outputs.host }}
depends-dep-opts: ${{ needs.depends-linux64.outputs.dep-opts }}
depends-artifact: ${{ needs.depends-linux64.outputs.built-artifact }}
depends-key: ${{ needs.depends-linux64_platform_gui.outputs.key }}
depends-host: ${{ needs.depends-linux64_platform_gui.outputs.host }}
depends-dep-opts: ${{ needs.depends-linux64_platform_gui.outputs.dep-opts }}
depends-artifact: ${{ needs.depends-linux64_platform_gui.outputs.built-artifact }}
runs-on: ${{ needs.check-skip.outputs['runner-amd64'] }}
secrets: *remote-ccache-auth

Expand Down
12 changes: 10 additions & 2 deletions .github/workflows/cache-depends-sources.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,23 @@ jobs:
allow-unsafe-pr-checkout: true
persist-credentials: false

# v2: caches from before the Platform GUI step below lack its sources.
- name: Check for cached sources
id: cache-check
uses: actions/cache@v5
with:
path: depends/sources
key: depends-sources-${{ hashFiles('depends/packages/*') }}
restore-keys: depends-sources-
key: depends-sources-v2-${{ hashFiles('depends/packages/*') }}
restore-keys: depends-sources-v2-
lookup-only: true

- name: Download sources
if: steps.cache-check.outputs.cache-hit != 'true'
run: make -C depends download

# The linux64_platform_gui depends job runs on x86_64, but this runner
# may not: name the build machine, since the Rust toolchain and protoc
# archives are chosen by it. download-linux would not pass BUILD on.
- name: Download Platform GUI sources for x86_64 Linux
if: steps.cache-check.outputs.cache-hit != 'true'
run: make -C depends download-one PLATFORM_GUI=1 BUILD=x86_64-pc-linux-gnu HOST=x86_64-unknown-linux-gnu
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ share/qt/Info.plist

src/qt/*.moc
src/qt/moc_*.cpp
src/qt/platform/moc_*.cpp
src/qt/forms/ui_*.h

src/qt/test/moc*.cpp
Expand Down
4 changes: 4 additions & 0 deletions ci/dash/build_src.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ if [ "${RUN_STDLIB_PATH_CHECK}" = "true" ]; then
make -C src --jobs=1 check-stdlib-paths
fi

if [ "${RUN_CHECK_NO_RUST}" = "true" ]; then
"${BASE_ROOT_DIR}/contrib/devtools/check-no-rust.py" src/dashd src/dash-cli src/dash-tx src/dash-util src/dash-wallet src/test/fuzz/fuzz
fi

if [ -n "$USE_VALGRIND" ]; then
echo "valgrind in USE!"
"${BASE_ROOT_DIR}/ci/test/wrap-valgrind.sh"
Expand Down
2 changes: 2 additions & 0 deletions ci/dash/matrix.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ elif [ "$BUILD_TARGET" = "linux64_multiprocess" ]; then
source ./ci/test/00_setup_env_native_multiprocess.sh
elif [ "$BUILD_TARGET" = "linux64_nowallet" ]; then
source ./ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh
elif [ "$BUILD_TARGET" = "linux64_platform_gui" ]; then
source ./ci/test/00_setup_env_native_platform_gui.sh
elif [ "$BUILD_TARGET" = "linux64_sqlite" ]; then
source ./ci/test/00_setup_env_native_sqlite.sh
elif [ "$BUILD_TARGET" = "linux64_tsan" ]; then
Expand Down
12 changes: 12 additions & 0 deletions ci/test/00_setup_env_native_platform_gui.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
#
# Copyright (c) 2026 The Dash Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

export LC_ALL=C.UTF-8

# Depends with dash-sdk-cxx (PLATFORM_GUI=1); linux64_sqlite builds against it.
export CONTAINER_NAME=ci_native_platform_gui
export HOST=x86_64-pc-linux-gnu
export DEP_OPTS="PLATFORM_GUI=1"
1 change: 1 addition & 0 deletions ci/test/00_setup_env_native_sqlite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libhar
export DEP_OPTS="NO_BDB=1 NO_UPNP=1 DEBUG=1"
export GOAL="install"
export BITCOIN_CONFIG="--enable-zmq --enable-reduce-exports --with-sqlite --without-bdb CC=gcc-11 CXX=g++-11"
export RUN_CHECK_NO_RUST="true"
44 changes: 44 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,14 @@ if test "$enable_miner" = "yes"; then
AC_DEFINE(ENABLE_MINER, 1, [Define this symbol if in-wallet miner should be enabled])
fi

AC_ARG_ENABLE([platform-gui],
[AS_HELP_STRING([--enable-platform-gui],
[enable Dash Platform (usernames, DashPay contacts) in the GUI; requires the GUI, the wallet and the Dash Platform SDK's C++ binding (dash-sdk-cxx) built by depends with PLATFORM_GUI=1 (default is no)])],
[enable_platform_gui=$enableval],
[enable_platform_gui=no])
AC_ARG_VAR([PLATFORM_CXX_CFLAGS], [C++ compiler flags for dash-sdk-cxx, overriding pkg-config])
AC_ARG_VAR([PLATFORM_CXX_LIBS], [Linker flags for dash-sdk-cxx, overriding pkg-config (default: the library and the vetted system libraries from the depends dash_sdk_cxx.pc)])

dnl Enable different -fsanitize options
AC_ARG_WITH([sanitizers],
[AS_HELP_STRING([--with-sanitizers],
Expand Down Expand Up @@ -1926,6 +1934,41 @@ if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_
AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-fuzz(-binary) --enable-bench or --enable-tests])
fi

dnl dash-sdk-cxx, the C++ binding of the Dash Platform SDK, is a Rust static
dnl library linked into dash-qt (and its tests) only. depends installs
dnl dash_sdk_cxx.pc, whose Libs are the library and the vetted system libraries
dnl it needs; depends checks those against rustc's --print=native-static-libs.
if test "$enable_platform_gui" = "yes"; then
if test "$bitcoin_enable_qt" != "yes"; then
AC_MSG_ERROR([--enable-platform-gui requires the GUI])
fi
if test "$enable_wallet" != "yes"; then
AC_MSG_ERROR([--enable-platform-gui requires the wallet])
fi
PKG_CHECK_MODULES([PLATFORM_CXX], [dash_sdk_cxx], [],
[AC_MSG_ERROR([--enable-platform-gui requires dash-sdk-cxx (build depends with PLATFORM_GUI=1)])])
TEMP_CPPFLAGS="$CPPFLAGS"
TEMP_LIBS="$LIBS"
CPPFLAGS="$CPPFLAGS $PLATFORM_CXX_CFLAGS"
LIBS="$PLATFORM_CXX_LIBS $LIBS"
AC_LANG_PUSH([C++])
AC_MSG_CHECKING([whether a program using dash-sdk-cxx links])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <dash/sdk/ffi.h>
]], [[
rust::Box<dash_sdk::PlatformClient> client{dash_sdk::new_platform_client(dash_sdk::Config{}, nullptr)};
client->shutdown();
]])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([a program using dash-sdk-cxx does not link; see config.log])])
AC_LANG_POP([C++])
CPPFLAGS="$TEMP_CPPFLAGS"
LIBS="$TEMP_LIBS"
AC_DEFINE([ENABLE_PLATFORM_GUI], [1], [Define this symbol to enable Dash Platform support in the GUI])
fi
AM_CONDITIONAL([ENABLE_PLATFORM_GUI], [test "$enable_platform_gui" = "yes"])

AM_CONDITIONAL([TARGET_DARWIN], [test "$TARGET_OS" = "darwin"])
AM_CONDITIONAL([BUILD_DARWIN], [test "$BUILD_OS" = "darwin"])
AM_CONDITIONAL([TARGET_LINUX], [test "$TARGET_OS" = "linux"])
Expand Down Expand Up @@ -2121,6 +2164,7 @@ echo " debug enabled = $enable_debug"
echo " stacktraces = $enable_stacktraces"
echo " crash hooks = $enable_crashhooks"
echo " miner enabled = $enable_miner"
echo " platform gui = $enable_platform_gui"
echo " werror = $enable_werror"
echo
echo " target os = $host_os"
Expand Down
34 changes: 34 additions & 0 deletions contrib/devtools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,37 @@ Example usage:

cd .../src
../contrib/devtools/circular-dependencies.py {*,*/*,*/*/*}.{h,cpp}

update-rust-hashes.py
=====================

Refreshes the sha256 pins of the prebuilt Rust toolchain
(`depends/packages/native_rust.mk`) and of the per-host standard libraries
(`depends/packages/rust_stdlib.mk`) after the version in `native_rust.mk` was
changed; each downloaded archive must match the `.sha256` file published next
to it. `--check` compares the pins with the published `.sha256` files instead
of rewriting them.

platform-bundle.sh
==================

Produces the crate bundle from which `depends/packages/platform_cxx.mk` builds
`dash-sdk-cxx` (the C++ binding of the Dash Platform SDK) for a given
`dashpay/platform` commit, and prints the hashes to pin in `platform_cxx.mk`.
The bundle includes the Tenderdash source archive for the tag the commit's
`Cargo.lock` pins, so the two cannot disagree. Requires the Cargo version pinned in `native_rust.mk`,
GNU tar, GNU gzip (set `TAR` and `GZIP_PROG` if they are installed under other
names) and a `TMPDIR` with no `.cargo/config.toml` in any parent directory.
The output is reproducible: rerunning it for the same commit yields the same
bundle hash on any machine. The Platform tarball and the bundle are then
uploaded to the depends sources mirror.

contrib/devtools/platform-bundle.sh <platform-commit>

check-no-rust.py
================

Fails if any of the given executables contain Rust code. Run by the
`linux64_sqlite` CI job, which builds against depends with `PLATFORM_GUI=1`,
on `dashd`, the command-line tools and the fuzz binary, which must never link
`dash-sdk-cxx`.
64 changes: 64 additions & 0 deletions contrib/devtools/check-no-rust.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env python3
# Copyright (c) 2026 The Dash Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
Check that executables do not link Rust code.

dash-sdk-cxx, the Dash Platform SDK binding (--enable-platform-gui), is for
dash-qt only; dashd, the command-line tools and the fuzz binary must not
contain any of it.
A binary fails if its symbol table has cxx bridge, Rust runtime or Rust
standard library symbols, or has no symbols at all (a stripped binary cannot
be checked).

Example usage:

contrib/devtools/check-no-rust.py src/dashd src/dash-cli src/dash-tx src/dash-wallet src/test/fuzz/fuzz
'''
import re
import subprocess
import sys

from utils import determine_wellknown_cmd

# cxx bridge symbols carry "cxxbridge1$". Rust code is either legacy-mangled
# under a crate namespace (rust, std, core, alloc) or v0-mangled ("_R"
# followed by a path tag and a crate root "Cs<disambiguator>_"), which C and
# C++ symbols never match. The allocator shim, the panic handler and the
# unwinding personality are plain C names every Rust program links.
RUST_SYMBOL = re.compile(
r'cxxbridge1\$'
r'|_ZN(4rust|3std|4core|5alloc)[0-9]'
r'|\b_?_R[A-Za-z0-9_]*?Cs[A-Za-z0-9]*_[0-9]'
r'|\b_?(__rust_alloc|rust_begin_unwind|rust_eh_personality)'
)


def rust_symbols(nm, path):
result = subprocess.run(nm + [path], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False)
if result.returncode != 0:
sys.exit(f'{path}: {result.stderr.strip()}')
lines = result.stdout.splitlines()
if not lines:
sys.exit(f'{path}: no symbols, so it cannot be checked (stripped?)')
return [line for line in lines if RUST_SYMBOL.search(line)]


def main():
if len(sys.argv) < 2:
sys.exit(__doc__)
nm = determine_wellknown_cmd('NM', 'nm')
failed = False
for path in sys.argv[1:]:
found = rust_symbols(nm, path)
if found:
failed = True
print(f'{path}: links Rust code, for example:')
for line in found[:5]:
print(f' {line}')
sys.exit(1 if failed else 0)


if __name__ == '__main__':
main()
Loading
Loading