Skip to content

Commit 86bac79

Browse files
tgunnoeKlapeyron
authored andcommitted
feat: add nix build
1 parent 50a8248 commit 86bac79

File tree

6 files changed

+501
-1
lines changed

6 files changed

+501
-1
lines changed

dev/nix/nixos/default.nix

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
imports = import ./module-list.nix;
3+
}

dev/nix/nixos/module-list.nix

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
[
3+
./partner-chains-service.nix
4+
]
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
# Partner Chains Node NixOS module
2+
{self, ...}:
3+
{
4+
flake.nixosModules.partner-chains =
5+
{ config, lib, pkgs, ... }:
6+
7+
with lib;
8+
9+
let
10+
cfg = config.services.partner-chains;
11+
in {
12+
options.services.partner-chains = {
13+
enable = mkEnableOption "Partner Chains Node";
14+
15+
# Common environment variables
16+
environment = mkOption {
17+
type = types.attrsOf types.str;
18+
default = {
19+
CARDANO_SECURITY_PARAMETER = "432";
20+
CARDANO_ACTIVE_SLOTS_COEFF = "0.05";
21+
DB_SYNC_POSTGRES_CONNECTION_STRING = "postgresql://cexplorer:password@localhost:5432/cexplorer";
22+
MC__FIRST_EPOCH_TIMESTAMP_MILLIS = "1666656000000";
23+
MC__EPOCH_DURATION_MILLIS = "86400000";
24+
MC__SLOT_DURATION_MILLIS = "1000";
25+
MC__FIRST_EPOCH_NUMBER = "0";
26+
MC__FIRST_SLOT_NUMBER = "0";
27+
BLOCK_STABILITY_MARGIN = "0";
28+
};
29+
description = "Environment variables for the partner chains node";
30+
};
31+
32+
# Node-specific options
33+
nodeName = mkOption {
34+
type = types.nullOr types.str;
35+
default = null;
36+
example = "alice";
37+
description = "Node name flag (--alice, --bob, --charlie, etc.)";
38+
};
39+
40+
nodeKey = mkOption {
41+
type = types.str;
42+
example = "0a04cb23cff606facb13ddd43655840e9f6f32bd7b432809620d461596e188e9";
43+
description = "Node key for identification";
44+
};
45+
46+
chainSpecPath = mkOption {
47+
type = types.path;
48+
default = "/var/lib/partner-chains/chain-spec.json";
49+
description = "Path to the chain specification file";
50+
};
51+
52+
keystorePath = mkOption {
53+
type = types.path;
54+
default = "/var/lib/partner-chains/keystore";
55+
description = "Path to the keystore directory";
56+
};
57+
58+
listenAddr = mkOption {
59+
type = types.str;
60+
default = "/ip4/0.0.0.0/tcp/30333";
61+
description = "Address to listen on";
62+
};
63+
64+
prometheusPort = mkOption {
65+
type = types.int;
66+
default = 9615;
67+
description = "Prometheus metrics port";
68+
};
69+
70+
rpcPort = mkOption {
71+
type = types.int;
72+
default = 9944;
73+
description = "RPC server port";
74+
};
75+
76+
logLevel = mkOption {
77+
type = types.str;
78+
default = "runtime=debug";
79+
description = "Log level configuration";
80+
};
81+
82+
reservedNodes = mkOption {
83+
type = types.listOf types.str;
84+
default = [];
85+
example = ["/dns/dave.node.sc.iog.io/tcp/30333/p2p/12D3KooWH4LhgJDUbYbXsksQef4jTpDjA64ecUBjBVJprNzF64hE"];
86+
description = "List of reserved nodes";
87+
};
88+
89+
bootNodes = mkOption {
90+
type = types.listOf types.str;
91+
default = [];
92+
example = ["/dns/eve.node.sc.iog.io/tcp/30333/p2p/12D3KooWN3YiYbk9nMZJ2VG7uk9iKfFWb1Kwrj7PoMdadfnAsRJm"];
93+
description = "List of boot nodes";
94+
};
95+
96+
extraArgs = mkOption {
97+
type = types.listOf types.str;
98+
default = [];
99+
example = ["--rpc-methods=unsafe" "--rpc-max-connections" "1000"];
100+
description = "Additional command line arguments";
101+
};
102+
103+
enableRpc = mkOption {
104+
type = types.bool;
105+
default = false;
106+
description = "Enable RPC server";
107+
};
108+
109+
rpcCors = mkOption {
110+
type = types.str;
111+
default = "all";
112+
description = "RPC CORS setting";
113+
};
114+
115+
blockBeneficiary = mkOption {
116+
type = types.str;
117+
example = "0a04cb23cff606facb13ddd43655840e9f6f32bd7b432809620d461596e188e9";
118+
description = "Sidechain block beneficiary address";
119+
};
120+
121+
package = mkOption {
122+
type = types.package;
123+
default = pkgs.partner-chains.packages.x86_64-linux.partner-chains;
124+
description = "The partner-chains package to use";
125+
};
126+
127+
# New options
128+
enableValidator = mkOption {
129+
type = types.bool;
130+
default = false;
131+
description = "Enable validator mode";
132+
};
133+
134+
pruning = mkOption {
135+
type = types.enum [ "default" "archive" ];
136+
default = "default";
137+
description = "Pruning mode for the blockchain data";
138+
};
139+
};
140+
141+
config = mkIf cfg.enable {
142+
systemd.services.partner-chains = {
143+
description = "Partner Chains Node";
144+
wantedBy = [ "multi-user.target" ];
145+
after = [ "network.target" ];
146+
147+
# Combine the default environment with any overrides
148+
environment = cfg.environment // {
149+
SIDECHAIN_BLOCK_BENEFICIARY = cfg.blockBeneficiary;
150+
};
151+
152+
preStart = ''
153+
# Ensure directories exist
154+
mkdir -p ${dirOf cfg.chainSpecPath}
155+
mkdir -p ${cfg.keystorePath}
156+
157+
# Create a default chain spec if it doesn't exist
158+
if [ ! -f "${cfg.chainSpecPath}" ]; then
159+
echo "Chain spec file does not exist at ${cfg.chainSpecPath}"
160+
echo "Creating a minimal placeholder. Please ensure a proper chain spec is configured."
161+
echo '{"name": "partner-chains", "id": "partner-chains"}' > ${cfg.chainSpecPath}
162+
fi
163+
164+
# Set proper permissions
165+
chown -R partner-chains:partner-chains ${dirOf cfg.chainSpecPath}
166+
chown -R partner-chains:partner-chains ${cfg.keystorePath}
167+
chmod 750 ${dirOf cfg.chainSpecPath}
168+
chmod 750 ${cfg.keystorePath}
169+
chmod 640 ${cfg.chainSpecPath}
170+
171+
# Create data directories with proper permissions
172+
DATA_DIR=$(dirname ${cfg.keystorePath})
173+
if [ ! -d "$DATA_DIR" ]; then
174+
mkdir -p $DATA_DIR
175+
chown -R partner-chains:partner-chains $DATA_DIR
176+
chmod -R 750 $DATA_DIR
177+
fi
178+
'';
179+
180+
serviceConfig = let
181+
# Node name flag (--alice, --bob, etc.)
182+
nodeNameFlag = if cfg.nodeName != null then "--${cfg.nodeName}" else "";
183+
184+
# Reserved nodes flags
185+
reservedNodesFlags = if cfg.reservedNodes != []
186+
then ["--reserved-only"] ++ (flatten (map (node: ["--reserved-nodes" node]) cfg.reservedNodes))
187+
else [];
188+
189+
# Boot nodes flags
190+
bootNodesFlags = flatten (map (node: ["--bootnodes" node]) cfg.bootNodes);
191+
192+
# RPC flags
193+
rpcFlags = if cfg.enableRpc
194+
then ["--rpc-external" "--rpc-cors=${cfg.rpcCors}" "--rpc-port" (toString cfg.rpcPort)]
195+
else [];
196+
197+
# Pruning flags
198+
pruningFlags = if cfg.pruning == "archive"
199+
then ["--state-pruning" "archive" "--blocks-pruning" "archive"]
200+
else [];
201+
202+
# Combine all arguments
203+
allArgs =
204+
[nodeNameFlag]
205+
++ (optional cfg.enableValidator "--validator")
206+
++ ["--node-key" cfg.nodeKey]
207+
++ ["--chain" cfg.chainSpecPath]
208+
++ reservedNodesFlags
209+
++ bootNodesFlags
210+
++ ["-llibp2p=debug"]
211+
++ ["--listen-addr" cfg.listenAddr]
212+
++ ["--keystore-path" cfg.keystorePath]
213+
++ ["--log" cfg.logLevel]
214+
++ ["--prometheus-port" (toString cfg.prometheusPort)]
215+
++ ["--prometheus-external"]
216+
++ rpcFlags
217+
++ pruningFlags
218+
++ cfg.extraArgs;
219+
220+
# Filter out empty strings (from nodeNameFlag if it's empty)
221+
cleanArgs = filter (arg: arg != "") allArgs;
222+
in {
223+
ExecStart = "${cfg.package}/bin/partner-chains-node ${concatStringsSep " " cleanArgs}";
224+
225+
# Important! Create a StateDirectory for persistent storage
226+
StateDirectory = "partner-chains";
227+
228+
# This ensures systemd captures all stdout/stderr
229+
StandardOutput = "journal";
230+
StandardError = "journal";
231+
232+
# Security hardening
233+
User = "partner-chains";
234+
Group = "partner-chains";
235+
Restart = "always";
236+
RestartSec = "10s";
237+
LimitNOFILE = 65535;
238+
};
239+
};
240+
241+
# Create the user/group
242+
users.users.partner-chains = {
243+
isSystemUser = true;
244+
group = "partner-chains";
245+
home = "/var/lib/partner-chains";
246+
createHome = true;
247+
};
248+
users.groups.partner-chains = {};
249+
250+
# Open firewall ports
251+
networking.firewall.allowedTCPPorts = [
252+
30333 # P2P port
253+
cfg.prometheusPort
254+
] ++ (optionals cfg.enableRpc [ cfg.rpcPort ]);
255+
};
256+
};
257+
}

dev/nix/packages/default.nix

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
{
2+
self,
3+
inputs,
4+
system,
5+
...
6+
}: {
7+
perSystem = {
8+
inputs',
9+
self',
10+
lib,
11+
pkgs,
12+
system,
13+
...
14+
}: let
15+
flake-compat = import inputs.flake-compat;
16+
cardanoPackages = (flake-compat { src = inputs.cardano-node; }).defaultNix.packages.${system};
17+
dbSyncPackages = (flake-compat { src = inputs.cardano-dbsync; }).defaultNix.packages.${system};
18+
fenixPkgs = inputs'.fenix.packages;
19+
rustToolchain = with fenixPkgs;
20+
fromToolchainFile {
21+
file = ../../../rust-toolchain.toml;
22+
sha256 = "X/4ZBHO3iW0fOenQ3foEvscgAPJYl2abspaBThDOukI=";
23+
};
24+
customRustPlatform = pkgs.makeRustPlatform {
25+
cargo = rustToolchain;
26+
rustc = rustToolchain;
27+
};
28+
29+
in {
30+
packages = {
31+
inherit (cardanoPackages) cardano-node cardano-cli cardano-testnet;
32+
inherit (dbSyncPackages) "cardano-db-sync:exe:cardano-db-sync";
33+
ogmios = pkgs.callPackage ./ogmios.nix { };
34+
process-compose = pkgs.process-compose.overrideAttrs (oldAttrs: {
35+
patches = [ ./pc.patch ];
36+
});
37+
partnerchains-stack = pkgs.callPackage ./partnerchains-stack { inherit (self'.packages) partnerchains-stack-unwrapped; };
38+
partnerchains-stack-unwrapped = pkgs.callPackage ./partnerchains-stack-unwrapped { };
39+
partner-chains = customRustPlatform.buildRustPackage rec {
40+
pname = "partner-chains";
41+
version = "1.6";
42+
src = ../../../.;
43+
preBuild = ''
44+
export SUBSTRATE_CLI_GIT_COMMIT_HASH=${self.dirtyShortRev or self.shortRev}
45+
'';
46+
47+
useFetchCargoVendor = true;
48+
cargoHash = "sha256-y0sHdHicouV3rRw2i17kfFXKQJlFcu0rtsKXs2SNVX0=";
49+
buildType = "production";
50+
#buildAndTestSubdir = dir;
51+
doCheck = false;
52+
patches = [];
53+
54+
nativeBuildInputs = [
55+
pkgs.pkg-config
56+
pkgs.protobuf
57+
58+
pkgs.llvmPackages.lld
59+
customRustPlatform.bindgenHook
60+
];
61+
buildInputs = [
62+
pkgs.rocksdb
63+
pkgs.openssl
64+
pkgs.libclang.lib
65+
] ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux [
66+
pkgs.rust-jemalloc-sys-unprefixed
67+
] ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isDarwin [
68+
pkgs.darwin.apple_sdk.frameworks.SystemConfiguration
69+
pkgs.darwin.apple_sdk.frameworks.Security
70+
];
71+
72+
postFixup = pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isLinux ''
73+
patchelf --set-rpath "${pkgs.rocksdb}/lib:${pkgs.stdenv.cc.cc.lib}/lib" $out/bin/partner-chains-demo-node
74+
'';
75+
76+
# Force skip support check in CC crate
77+
#CRATE_CC_NO_DEFAULTS = "1";
78+
79+
# Platform-specific features
80+
RUSTFLAGS = pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isDarwin
81+
"--cfg unwinding_backport --cfg unwinding_apple";
82+
83+
# Existing environment variables
84+
CC_ENABLE_DEBUG_OUTPUT = "1";
85+
#CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_LINKER = "${pkgs.llvmPackages.lld}/bin/lld";
86+
#RUST_SRC_PATH = "${customRustPlatform.rustLibSrc}";
87+
LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
88+
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [
89+
rustToolchain
90+
pkgs.stdenv.cc.cc
91+
pkgs.libz
92+
pkgs.clang
93+
];
94+
95+
# Platform-specific flags
96+
CFLAGS =
97+
if pkgs.lib.hasSuffix "linux" system then
98+
"-DJEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE"
99+
else
100+
"";
101+
102+
PROTOC = "${pkgs.protobuf}/bin/protoc";
103+
ROCKSDB_LIB_DIR = "${pkgs.rocksdb}/lib/";
104+
OPENSSL_NO_VENDOR = 1;
105+
OPENSSL_DIR = "${pkgs.openssl.dev}";
106+
OPENSSL_INCLUDE_DIR = "${pkgs.openssl.dev}/include";
107+
OPENSSL_LIB_DIR = "${pkgs.openssl.out}/lib";
108+
BINDGEN_EXTRA_CLANG_ARGS = "-I${pkgs.stdenv.cc.cc}/include -std=c++17";
109+
110+
};
111+
};
112+
};
113+
}

0 commit comments

Comments
 (0)