Skip to content

Commit 00d7016

Browse files
committed
Merge branch 'develop' into 2133-allow-creating-transactions-with-less-than-1-satvbyte-fee-rate
# Conflicts: # lib/features/send/ui/screens/send_screen.dart # test/features/send/presentation/bloc/send_state_test.dart
2 parents 128102d + 9cac660 commit 00d7016

229 files changed

Lines changed: 30960 additions & 642 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.devcontainer/README.md

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,81 @@
11
# Dev Container
22

3+
Two host-specific configurations live side by side. They build the **same**
4+
image (the repo-root `Containerfile.tools`) but each folder is
5+
**self-contained** — it carries its own copy of the lifecycle scripts it needs
6+
(they are not shared).
7+
They differ only in the host integration the runtime can provide:
8+
9+
| Config | Use on | Notable extras |
10+
| --- | --- | --- |
11+
| [`linux/devcontainer.json`](linux/devcontainer.json) | Linux hosts | GPU (`/dev/dri`), X11/Wayland forwarding, SSH-agent forwarding, gnome-keyring for the Flutter Linux desktop GUI |
12+
| [`macos/devcontainer.json`](macos/devcontainer.json) | macOS (Apple Silicon) | Rosetta bootstrap; GUI/GPU, SSH-agent and keyring all omitted (the VM can't provide them) |
13+
314
## Usage
415

16+
`make devcontainer` auto-selects the config for your host OS (override with
17+
`make devcontainer DEVCONTAINER_OS=linux|macos`). It **reuses an existing
18+
container if one is present** — it only builds/creates when no container exists
19+
yet, otherwise it just (re)starts it (replaying the Linux keyring bootstrap,
20+
which dies on stop). So stopping and starting is safe and never rebuilds.
21+
22+
The container is named **`bull`** — a static `--name` pinned in both `devcontainer.json` files and mirrored by `DEVCONTAINER_NAME` in the makefile — so repeated opens reuse the one container instead of creating a per-folder one. The workspace itself still mounts at `/workspaces/<checkout-folder>`. Because the name is shared, two different clones/worktrees can't each run their own container side by side: the second open attaches to whichever tree was mounted first.
23+
524
```bash
6-
devcontainer up --workspace-folder . --config ./.devcontainer/devcontainer.json
25+
make devcontainer # host-detected
26+
make devcontainer DEVCONTAINER_OS=linux # force linux
27+
make devcontainer DEVCONTAINER_OS=macos # force macos
728
```
829

9-
## macOS (Apple Silicon)
30+
> **Applying a config change:** because `make devcontainer` never recreates an
31+
> existing container, edits to `devcontainer.json` / `Containerfile.tools` won't
32+
> take effect until you remove the old container first:
33+
> `podman rm -f bull && make devcontainer`.
1034
11-
Before starting the container, run the setup script:
35+
Or invoke the CLI directly (this *will* recreate on a config change):
1236

1337
```bash
14-
.devcontainer/macos-setup.sh
38+
devcontainer up --workspace-folder . --config ./.devcontainer/linux/devcontainer.json
39+
devcontainer up --workspace-folder . --config ./.devcontainer/macos/devcontainer.json
1540
```
1641

17-
This ensures Rosetta is active in the Podman VM. Without it, x86_64 binaries fall back to QEMU and crash with SIGSEGV. See [containers/podman#28181](https://github.com/containers/podman/issues/28181).
42+
In VS Code, "Reopen in Container" prompts you to choose between the two.
43+
44+
> The `devcontainer` CLI builds its **own** image (`vsc-bull-…`) from
45+
> `Containerfile.tools`; it does not reuse the `bull-tools` tag from
46+
> `make container-tools` (that one bakes a different `USERNAME` and so shares no
47+
> layer cache). `make devcontainer` therefore has no `container-tools`
48+
> prerequisite — only `container-app`/`android` build `bull-tools`.
49+
50+
## macOS (Apple Silicon) notes
51+
52+
The macOS target is the Android (x86_64-via-Rosetta) build + tests, not the
53+
Linux desktop GUI. The macOS config is a trimmed sibling of the Linux one.
54+
55+
- **Rosetta** must be active in the podman VM, otherwise the linux/amd64 base
56+
image falls back to QEMU and crashes with SIGSEGV
57+
([containers/podman#28181](https://github.com/containers/podman/issues/28181)).
58+
It is on by default for Apple Silicon machines (podman ≥ 5.1).
59+
[`macos/macos-setup.sh`](macos/macos-setup.sh) runs automatically via
60+
`initializeCommand`; if Rosetta is off it sets the marker and restarts the
61+
machine (a service-only restart is not enough).
62+
- **No GUI / GPU forwarding.** `--device=/dev/dri` and the X11/Wayland mounts
63+
are dropped: applehv exposes no DRI node and macOS has no Linux display
64+
server.
65+
- **No SSH-agent forwarding.** Impossible through the podman VM on macOS
66+
(virtiofs; [containers/podman#23785](https://github.com/containers/podman/issues/23785)).
67+
The agent socket is not mounted at all; `~/.ssh` is still mounted read-only,
68+
so key-based (non-agent) auth works.
69+
- **No keyring/dbus bootstrap.** `flutter_secure_storage_linux` (libsecret)
70+
only exercises the Secret Service when the rendered Linux app runs, which
71+
macOS can't display — so the gnome-keyring bootstrap the Linux config does at
72+
`postStart` is omitted.
73+
74+
## adb device bridge (both configs)
1875

19-
**Note:** SSH agent forwarding is not supported on macOS due to Podman's inability to mount host Unix sockets into containers through the VM layer. See [containers/podman#23785](https://github.com/containers/podman/issues/23785).
76+
[`init-adb.sh`](linux/init-adb.sh) exposes the **host's** adb server to the
77+
container (`ADB_SERVER_SOCKET=tcp:host.containers.internal:5037`) so a host-side
78+
device or emulator is reachable from inside. Note it (re)starts the host adb
79+
server with `-a` (binds `0.0.0.0:5037`) — see the security note in the script
80+
before using it on an untrusted network. Host and container adb versions must
81+
match.

.devcontainer/devcontainer.json

Lines changed: 0 additions & 47 deletions
This file was deleted.

.devcontainer/init-ssh-agent.sh

Lines changed: 0 additions & 57 deletions
This file was deleted.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Linux host dev container. Builds ../../Containerfile.tools and forwards the
2+
// host GPU (/dev/dri) + X11/Wayland so the Flutter Linux desktop GUI can run.
3+
{
4+
"name": "bull",
5+
"build": {
6+
"dockerfile": "../../Containerfile.tools",
7+
"args": {
8+
"USERNAME": "${localEnv:USER}",
9+
},
10+
},
11+
"remoteUser": "${localEnv:USER}",
12+
"updateRemoteUserUID": true,
13+
"shutdownAction": "stopContainer",
14+
"initializeCommand": "sh -c '.devcontainer/linux/init-ssh-agent.sh && .devcontainer/linux/init-adb.sh'",
15+
"runArgs": [
16+
"--name",
17+
"bull",
18+
"--hostname",
19+
"bull",
20+
"--memory=8g",
21+
"--device=/dev/dri",
22+
// Pin DNS to public resolvers: podman's VM/netns default resolver has been
23+
// unreliable for pub.dev/crates.io fetches. On networks that require an
24+
// internal/split-horizon resolver (corp VPN, captive portal), drop or
25+
// change these two pairs.
26+
"--dns",
27+
"1.1.1.1",
28+
"--dns",
29+
"9.9.9.9",
30+
"--security-opt",
31+
"label=disable",
32+
],
33+
"mounts": [
34+
"source=${localEnv:HOME}/.ssh,target=/home/${localEnv:USER}/.ssh,type=bind,readonly",
35+
"source=${localEnv:HOME}/.ssh-agent-devcontainer.sock,target=/ssh-agent,type=bind",
36+
"source=${localEnv:HOME}/.gitconfig,target=/home/${localEnv:USER}/.gitconfig,type=bind",
37+
"source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind",
38+
"source=bull-bash-history,target=/home/${localEnv:USER}/.history,type=volume",
39+
"source=bull-keyrings,target=/home/${localEnv:USER}/.local/share/keyrings,type=volume",
40+
"source=${localEnv:XDG_RUNTIME_DIR},target=/run/host-runtime,type=bind",
41+
],
42+
"containerEnv": {
43+
"SSH_AUTH_SOCK": "/ssh-agent",
44+
"ADB_SERVER_SOCKET": "tcp:host.containers.internal:5037",
45+
"DISPLAY": "${localEnv:DISPLAY}",
46+
"XDG_RUNTIME_DIR": "/tmp",
47+
"WAYLAND_DISPLAY": "/run/host-runtime/${localEnv:WAYLAND_DISPLAY}",
48+
"GDK_BACKEND": "wayland,x11",
49+
"DBUS_SESSION_BUS_ADDRESS": "unix:path=/tmp/dbus-session.sock",
50+
},
51+
"postCreateCommand": "sudo chown -R ${localEnv:USER}:${localEnv:USER} /home/${localEnv:USER}/.local /home/${localEnv:USER}/.history && touch /home/${localEnv:USER}/.history/bash_history",
52+
"postStartCommand": ".devcontainer/linux/init-keyring.sh",
53+
}
Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,15 @@
1414
# replug). adb's server binds to 127.0.0.1 by default — unreachable from the
1515
# container's network namespace — so we (re)start it with -a (all interfaces).
1616
#
17-
# NOTE: host and container adb must be the same version (container ships
18-
# platform-tools 37.0.0); a mismatch makes adb refuse to connect.
17+
# SECURITY: -a binds the adb server to 0.0.0.0:5037, so any host on the same
18+
# network can drive it (install APKs, open an adb shell). adb has no per-
19+
# interface bind for its server, so on untrusted networks (cafe/airport Wi-Fi)
20+
# either skip this adb bridge or firewall tcp/5037 to localhost + the podman
21+
# gateway.
22+
#
23+
# NOTE: host and container adb must be the same version or adb refuses to
24+
# connect. The container's platform-tools is whatever sdkmanager ships latest
25+
# (unpinned), so match the host to the container's `adb --version`.
1926
set -e
2027

2128
# No adb on the host (or not on PATH) -> nothing to expose; the container falls
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,6 @@ if ! keyring_ok; then
7171
echo " killall -9 gnome-keyring-daemon dbus-daemon" >&2
7272
echo " rm -f /tmp/dbus-session.sock" >&2
7373
echo " rm -rf ~/.local/share/keyrings" >&2
74-
echo " .devcontainer/init-keyring.sh" >&2
74+
echo " .devcontainer/linux/init-keyring.sh" >&2
7575
exit 1
7676
fi
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/bin/sh
2+
# Linux host: normalize bind-mount sources for the Linux dev container.
3+
#
4+
# Every bind mount in devcontainer.json is a hard dependency: if its host
5+
# source is missing at create/start time, the container fails to come up.
6+
# This script guarantees every source exists — real when available, harmless
7+
# placeholder when not — so the container starts regardless of whether SSH,
8+
# git, or an agent are set up. Missing pieces degrade gracefully.
9+
#
10+
# The SSH agent socket lives under $HOME so it is reachable by the runtime.
11+
# Wayland needs no action here: the Linux config forwards the host's
12+
# XDG_RUNTIME_DIR at /run/host-runtime and points WAYLAND_DISPLAY at it.
13+
SSH_SOCKET="${HOME}/.ssh-agent-devcontainer.sock"
14+
15+
# ~/.ssh and ~/.gitconfig are bind-mounted into the container; a fresh machine
16+
# may lack either, which would fail the mount.
17+
mkdir -p "${HOME}/.ssh"
18+
[ -e "${HOME}/.gitconfig" ] || touch "${HOME}/.gitconfig"
19+
20+
# X11 socket dir bind-mounted at /tmp/.X11-unix. Absent on headless or
21+
# Wayland-only hosts — create it so the mount never fails (an empty dir just
22+
# means no X11 apps, not a broken container).
23+
mkdir -p /tmp/.X11-unix
24+
25+
# SSH agent: only symlink a *real* agent socket. If no agent is running,
26+
# $SSH_AUTH_SOCK is empty/stale — `ln -sf "" ...` would make a broken link.
27+
# Leave a placeholder file instead so the mount succeeds; the agent is simply
28+
# unavailable inside the container.
29+
if [ -n "$SSH_AUTH_SOCK" ] && [ -S "$SSH_AUTH_SOCK" ]; then
30+
ln -sf "$SSH_AUTH_SOCK" "$SSH_SOCKET"
31+
else
32+
rm -f "$SSH_SOCKET"
33+
touch "$SSH_SOCKET"
34+
fi

.devcontainer/macos-setup.sh

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
 (0)