Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Comment thread
PastaPastaPasta marked this conversation as resolved.
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