6 Commits

Author SHA1 Message Date
Luke Parker
0849d60f28 Run Bitcoin, Monero nodes on Alpine
While prior this didn't work well, presumably due to stack size limitations,
a shell script is included to raise the default stack size limit. This should
be tried again.
2025-12-08 02:30:34 -05:00
Luke Parker
3a792f9ce5 Update documentation on the serai-runtime build.rs 2025-12-08 02:22:29 -05:00
Luke Parker
50959fa0e3 Update the polkadot-sdk used
Removes `parity-wasm` as a dependency, closing
https://github.com/serai-dex/issues/227 and tidying our `deny.toml`.

This removes the `import-memory` flag from the linker as part of
`parity-wasm`'s usage was to map imports into exports
(5a1128b94b/substrate/client/executor/common/src/runtime_blob/runtime_blob.rs (L91-L142)).
2025-12-08 02:22:25 -05:00
Luke Parker
2fb90ebe55 Extend crates we patch to be empty from the Ethereum ecosystem
`ruint` pulls in many versions of many crates. This has it pull in less.
2025-12-06 08:27:34 -05:00
Luke Parker
b24adcbd14 Add panic-on-poison to no-std std_shims::sync::Mutex
We already had this behavior on `std`. It was omitted when no-`std` due to
deferring to `spin::Mutex`, which does not track poisoning at all. This
increases the parity of the two.

Part of https://github.com/serai-dex/serai/issues/698.
2025-12-06 08:06:38 -05:00
Luke Parker
b791256648 Remove substrate-wasm-builder
By defining our own build script, we gain complete clarity and control over how
the WASM is built. This also removes the need to patch the upstream due to it
allowing pollution of the environment variables from the host.

Notable appreciation is given to
https://github.com/rust-lang/rust/issues/145491 for identifying an issue
encountered here, with the associated PR clarifying the necessary flags for the
linker to fix this.
2025-12-04 23:23:38 -05:00
24 changed files with 588 additions and 319 deletions

434
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -184,7 +184,11 @@ alloy-eip2124 = { path = "patches/ethereum/alloy-eip2124" }
ark-ff-3 = { package = "ark-ff", path = "patches/ethereum/ark-ff-0.3" } ark-ff-3 = { package = "ark-ff", path = "patches/ethereum/ark-ff-0.3" }
ark-ff-4 = { package = "ark-ff", path = "patches/ethereum/ark-ff-0.4" } ark-ff-4 = { package = "ark-ff", path = "patches/ethereum/ark-ff-0.4" }
c-kzg = { path = "patches/ethereum/c-kzg" } c-kzg = { path = "patches/ethereum/c-kzg" }
secp256k1-30 = { package = "secp256k1", path = "patches/ethereum/secp256k1-30" } fastrlp-3 = { package = "fastrlp", path = "patches/ethereum/fastrlp-0.3" }
fastrlp-4 = { package = "fastrlp", path = "patches/ethereum/fastrlp-0.4" }
primitive-types-12 = { package = "primitive-types", path = "patches/ethereum/primitive-types-0.12" }
rlp = { path = "patches/ethereum/rlp" }
secp256k1-30 = { package = "secp256k1", path = "patches/ethereum/secp256k1-0.30" }
# Dependencies from monero-oxide which originate from within our own tree, potentially shimmed to account for deviations since publishing # Dependencies from monero-oxide which originate from within our own tree, potentially shimmed to account for deviations since publishing
std-shims = { path = "patches/std-shims" } std-shims = { path = "patches/std-shims" }

View File

@@ -6,12 +6,63 @@ pub use std::sync::{Arc, Weak};
mod mutex_shim { mod mutex_shim {
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
pub use spin::{Mutex, MutexGuard}; mod spin_mutex {
use core::ops::{Deref, DerefMut};
// We wrap this in an `Option` so we can consider `None` as poisoned
pub(super) struct Mutex<T>(spin::Mutex<Option<T>>);
/// An acquired view of a `Mutex`.
pub struct MutexGuard<'mutex, T> {
mutex: spin::MutexGuard<'mutex, Option<T>>,
// This is `Some` for the lifetime of this guard, and is only represented as an `Option` due
// to needing to move it on `Drop` (which solely gives us a mutable reference to `self`)
value: Option<T>,
}
impl<T> Mutex<T> {
pub(super) const fn new(value: T) -> Self {
Self(spin::Mutex::new(Some(value)))
}
pub(super) fn lock(&self) -> MutexGuard<'_, T> {
let mut mutex = self.0.lock();
// Take from the `Mutex` so future acquisitions will see `None` unless this is restored
let value = mutex.take();
// Check the prior acquisition did in fact restore the value
if value.is_none() {
panic!("locking a `spin::Mutex` held by a thread which panicked");
}
MutexGuard { mutex, value }
}
}
impl<T> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
self.value.as_ref().expect("no value yet checked upon lock acquisition")
}
}
impl<T> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
self.value.as_mut().expect("no value yet checked upon lock acquisition")
}
}
impl<'mutex, T> Drop for MutexGuard<'mutex, T> {
fn drop(&mut self) {
// Restore the value
*self.mutex = self.value.take();
}
}
}
#[cfg(not(feature = "std"))]
pub use spin_mutex::*;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std::sync::{Mutex, MutexGuard}; pub use std::sync::{Mutex, MutexGuard};
/// A shimmed `Mutex` with an API mutual to `spin` and `std`. /// A shimmed `Mutex` with an API mutual to `spin` and `std`.
#[derive(Default, Debug)]
pub struct ShimMutex<T>(Mutex<T>); pub struct ShimMutex<T>(Mutex<T>);
impl<T> ShimMutex<T> { impl<T> ShimMutex<T> {
/// Construct a new `Mutex`. /// Construct a new `Mutex`.
@@ -21,8 +72,9 @@ mod mutex_shim {
/// Acquire a lock on the contents of the `Mutex`. /// Acquire a lock on the contents of the `Mutex`.
/// ///
/// On no-`std` environments, this may spin until the lock is acquired. On `std` environments, /// This will panic if the `Mutex` was poisoned.
/// this may panic if the `Mutex` was poisoned. ///
/// On no-`std` environments, the implementation presumably defers to that of a spin lock.
pub fn lock(&self) -> MutexGuard<'_, T> { pub fn lock(&self) -> MutexGuard<'_, T> {
#[cfg(feature = "std")] #[cfg(feature = "std")]
let res = self.0.lock().unwrap(); let res = self.0.lock().unwrap();

View File

@@ -7,8 +7,7 @@ db-urls = ["https://github.com/rustsec/advisory-db"]
yanked = "deny" yanked = "deny"
ignore = [ ignore = [
"RUSTSEC-2022-0061", # https://github.com/serai-dex/serai/227 "RUSTSEC-2024-0370", # `proc-macro-error` is unmaintained, in-tree due to Substrate/`litep2p`
"RUSTSEC-2024-0370", # proc-macro-error is unmaintained
"RUSTSEC-2024-0436", # paste is unmaintained "RUSTSEC-2024-0436", # paste is unmaintained
] ]

View File

@@ -0,0 +1,166 @@
# Raises `PT_GNU_STACK`'s memory to be at least 8 MB.
#
# This causes `musl` to use a 8 MB default for new threads, resolving the primary
# compatibility issue faced when executing a program on a `musl` system.
#
# See https://wiki.musl-libc.org/functional-differences-from-glibc.html#Thread-stack-size
# for reference. This differs that instead of setting at time of link, it
# patches the binary as an already-linked ELF executable.
#!/bin/bash
set -eo pipefail
ELF="$1"
if [ ! -f "$ELF" ]; then
echo "\`increase_default_stack_size.sh\` [ELF binary]"
echo ""
echo "Sets the \`PT_GNU_STACK\` program header to its existing value or 8 MB,"
echo "whichever is greater."
exit 1
fi
function hex {
hexdump -e '1 1 "%.2x"' -v
}
function read_bytes {
dd status=none bs=1 skip=$1 count=$2 if="$ELF" | hex
}
function write_bytes {
POS=$1
BYTES=$2
while [ ! $BYTES = "" ]; do
printf "\x$(printf $BYTES | head -c2)" | dd status=none conv=notrunc bs=1 seek=$POS of="$ELF"
# Start with the third byte, as in, after the first two bytes
BYTES=$(printf $BYTES | tail -c+3)
POS=$(($POS + 1))
done
}
# Magic
MAGIC=$(read_bytes 0 4)
if [ ! $MAGIC = $(printf "\x7fELF" | hex) ]; then
echo "Not ELF"
exit 2
fi
# 1 if 32-bit, 2 if 64-bit
BITS=$(read_bytes 4 1)
case $BITS in
"01") BITS=32;;
"02") BITS=64;;
*)
echo "Not 32- or 64- bit"
exit 3
;;
esac
# For `value_per_bits a b`, `a` if 32-bit and `b` if 64-bit
function value_per_bits {
RESULT=$(($1))
if [ $BITS = 64 ]; then
RESULT=$(($2))
fi
printf $RESULT
}
# Read an integer by its offset, differing depending on if 32- or 64-bit
function read_integer_by_offset {
OFFSET=$(value_per_bits $1 $2)
printf $(( 0x$(swap_native_endian $(read_bytes $OFFSET $3)) ))
}
# 1 if little-endian, 2 if big-endian
LITTLE_ENDIAN=$(read_bytes 5 1)
case $LITTLE_ENDIAN in
"01") LITTLE_ENDIAN=1;;
"02") LITTLE_ENDIAN=0;;
*)
echo "Not little- or big- endian"
exit 4
;;
esac
# While this script is written in big-endian, we need to work with the file in
# its declared endian. This function swaps from big to native, or vice versa,
# as necessary.
function swap_native_endian {
BYTES="$1"
if [ "$BYTES" = "" ]; then
read BYTES
fi
if [ $LITTLE_ENDIAN -eq 0 ]; then
printf $BYTES
return
fi
while [ ! $BYTES = "" ]; do
printf $(printf $BYTES | tail -c2)
BYTES=$(printf $BYTES | head -c-2)
done
}
ELF_VERSION=$(read_bytes 6 1)
if [ ! $ELF_VERSION = "01" ]; then
echo "Unknown ELF Version ($ELF_VERSION)"
exit 5
fi
ELF_VERSION_2=$(read_bytes $((0x14)) 4)
if [ ! $ELF_VERSION_2 = $(swap_native_endian 00000001) ]; then
echo "Unknown secondary ELF Version ($ELF_VERSION_2)"
exit 6
fi
# Find where the program headers are
PROGRAM_HEADERS_OFFSET=$(read_integer_by_offset 0x1c 0x20 $(value_per_bits 4 8))
PROGRAM_HEADER_SIZE=$(value_per_bits 0x20 0x38)
DECLARED_PROGRAM_HEADER_SIZE=$(read_integer_by_offset 0x2a 0x36 2)
if [ ! $PROGRAM_HEADER_SIZE -eq $DECLARED_PROGRAM_HEADER_SIZE ]; then
echo "Unexpected size of a program header ($DECLARED_PROGRAM_HEADER_SIZE)"
exit 7
fi
function program_header_start {
printf $(($PROGRAM_HEADERS_OFFSET + ($1 * $PROGRAM_HEADER_SIZE)))
}
function read_program_header {
read_bytes $(program_header_start $1) $PROGRAM_HEADER_SIZE
}
# Iterate over each program header
PROGRAM_HEADERS=$(read_integer_by_offset 0x2c 0x38 2)
NEXT_PROGRAM_HEADER=$(( $PROGRAM_HEADERS - 1 ))
FOUND=0
while [ $NEXT_PROGRAM_HEADER -ne -1 ]; do
THIS_PROGRAM_HEADER=$NEXT_PROGRAM_HEADER
NEXT_PROGRAM_HEADER=$(( $NEXT_PROGRAM_HEADER - 1 ))
PROGRAM_HEADER=$(read_program_header $THIS_PROGRAM_HEADER)
HEADER_TYPE=$(printf $PROGRAM_HEADER | head -c8)
# `PT_GNU_STACK`
# https://github.com/torvalds/linux/blob/c2f2b01b74be8b40a2173372bcd770723f87e7b2/include/uapi/linux/elf.h#L41
if [ ! "$(swap_native_endian $HEADER_TYPE)" = "6474e551" ]; then
continue
fi
FOUND=1
MEMSZ_OFFSET=$(( $(program_header_start $THIS_PROGRAM_HEADER) + $(value_per_bits 0x14 0x28) ))
MEMSZ_LEN=$(value_per_bits 4 8)
# `MEMSZ_OFFSET MEMSZ_OFFSET` as we've already derived it depending on the amount of bits
MEMSZ=$(read_integer_by_offset $MEMSZ_OFFSET $MEMSZ_OFFSET $MEMSZ_LEN)
DESIRED_STACK_SIZE=$((8 * 1024 * 1024))
# Only run if the inherent value is _smaller_
if [ $MEMSZ -lt $DESIRED_STACK_SIZE ]; then
# `2 *`, as this is its length in hexadecimal
HEX_MEMSZ=$(printf %."$((2 * $MEMSZ_LEN))"x $DESIRED_STACK_SIZE)
write_bytes $MEMSZ_OFFSET $(swap_native_endian $HEX_MEMSZ)
fi
done
if [ $FOUND -eq 0 ]; then
echo "\`PT_GNU_STACK\` program header not found"
exit 8
fi
echo "All instances of \`PT_GNU_STACK\` patched to be at least 8 MB"
exit 0

View File

@@ -37,6 +37,6 @@ COPY --from=builder /bin/busybox /bin/
ENV LD_LIBRARY_PATH=/lib/ ENV LD_LIBRARY_PATH=/lib/
ENV PATH=/bin ENV PATH=/bin
# Copy the artifact itself # Copy the artifact itself
COPY --from=builder /serai/target/release/wbuild/serai-runtime/serai_runtime.wasm /serai.wasm COPY --from=builder /serai/target/release/serai_runtime.wasm /serai.wasm
# By default, copy the artifact to `/volume`, presumably a provided volume # By default, copy the artifact to `/volume`, presumably a provided volume
CMD ["busybox", "cp", "/serai.wasm", "/volume/serai.wasm"] CMD ["busybox", "cp", "/serai.wasm", "/volume/serai.wasm"]

View File

@@ -29,7 +29,7 @@ RUN tar xzvf bitcoin-${BITCOIN_VERSION}-$(uname -m)-linux-gnu.tar.gz
RUN mv bitcoin-${BITCOIN_VERSION}/bin/bitcoind . RUN mv bitcoin-${BITCOIN_VERSION}/bin/bitcoind .
"#; "#;
let setup = mimalloc(Os::Debian) + DOWNLOAD_BITCOIN; let setup = mimalloc(Os::Alpine) + DOWNLOAD_BITCOIN;
let run_bitcoin = format!( let run_bitcoin = format!(
r#" r#"
@@ -43,7 +43,7 @@ CMD ["/run.sh"]
network.label() network.label()
); );
let run = os(Os::Debian, "", "bitcoin") + &run_bitcoin; let run = os(Os::Alpine, "", "bitcoin") + &run_bitcoin;
let res = setup + &run; let res = setup + &run;
let mut bitcoin_path = orchestration_path.to_path_buf(); let mut bitcoin_path = orchestration_path.to_path_buf();

View File

@@ -21,7 +21,7 @@ fn monero_internal(
}; };
#[rustfmt::skip] #[rustfmt::skip]
let download_monero = format!(r#" let mut download_monero = format!(r#"
FROM alpine:latest AS monero FROM alpine:latest AS monero
RUN apk --no-cache add wget gnupg RUN apk --no-cache add wget gnupg
@@ -41,6 +41,16 @@ RUN tar -xvjf monero-linux-{arch}-v{MONERO_VERSION}.tar.bz2 --strip-components=1
network.label(), network.label(),
); );
if os == Os::Alpine {
// Increase the default stack size, as Monero does heavily use its stack
download_monero += &format!(
r#"
ADD orchestration/increase_default_stack_size.sh .
RUN ./increase_default_stack_size.sh {monero_binary}
"#
);
}
let setup = mimalloc(os) + &download_monero; let setup = mimalloc(os) + &download_monero;
let run_monero = format!( let run_monero = format!(
@@ -69,13 +79,13 @@ CMD ["/run.sh"]
} }
pub fn monero(orchestration_path: &Path, network: Network) { pub fn monero(orchestration_path: &Path, network: Network) {
monero_internal(network, Os::Debian, orchestration_path, "monero", "monerod", "18080 18081") monero_internal(network, Os::Alpine, orchestration_path, "monero", "monerod", "18080 18081")
} }
pub fn monero_wallet_rpc(orchestration_path: &Path) { pub fn monero_wallet_rpc(orchestration_path: &Path) {
monero_internal( monero_internal(
Network::Dev, Network::Dev,
Os::Debian, Os::Alpine,
orchestration_path, orchestration_path,
"monero-wallet-rpc", "monero-wallet-rpc",
"monero-wallet-rpc", "monero-wallet-rpc",

View File

@@ -0,0 +1,19 @@
[package]
name = "fastrlp"
version = "0.3.99"
description = "Patch to an empty crate"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/ethereum/fastrlp-0.3"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = []
edition = "2021"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[workspace]
[features]
alloc = []
std = []

View File

@@ -0,0 +1,19 @@
[package]
name = "fastrlp"
version = "0.4.99"
description = "Patch to an empty crate"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/ethereum/fastrlp-0.4"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = []
edition = "2021"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[workspace]
[features]
alloc = []
std = []

View File

@@ -0,0 +1 @@
const _NEVER_COMPILED: [(); 0 - 1] = [(); 0 - 1];

View File

@@ -0,0 +1,18 @@
[package]
name = "primitive-types"
version = "0.12.99"
description = "Patch to an empty crate"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/ethereum/primitive-types"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = []
edition = "2021"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[workspace]
[features]
std = []

View File

@@ -0,0 +1 @@
const _NEVER_COMPILED: [(); 0 - 1] = [(); 0 - 1];

View File

@@ -0,0 +1,18 @@
[package]
name = "rlp"
version = "0.5.99"
description = "Patch to an empty crate"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/ethereum/rlp"
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = []
edition = "2021"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[workspace]
[features]
std = []

View File

@@ -0,0 +1 @@
const _NEVER_COMPILED: [(); 0 - 1] = [(); 0 - 1];

View File

@@ -3,7 +3,7 @@ name = "secp256k1"
version = "0.30.99" version = "0.30.99"
description = "Patch to an empty crate" description = "Patch to an empty crate"
license = "MIT" license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/patches/ethereum/secp256k1-30" repository = "https://github.com/serai-dex/serai/tree/develop/patches/ethereum/secp256k1-0.30"
authors = ["Luke Parker <lukeparker5132@gmail.com>"] authors = ["Luke Parker <lukeparker5132@gmail.com>"]
keywords = [] keywords = []
edition = "2021" edition = "2021"

View File

@@ -0,0 +1 @@
const _NEVER_COMPILED: [(); 0 - 1] = [(); 0 - 1];

View File

@@ -74,7 +74,7 @@ fn wasm_binary(dev: bool) -> Vec<u8> {
} }
log::info!("using built-in wasm"); log::info!("using built-in wasm");
serai_runtime::WASM_BINARY.ok_or("compiled in wasm not available").unwrap().to_vec() serai_runtime::WASM.to_vec()
} }
fn devnet_genesis(validators: &[&'static str], endowed_accounts: Vec<Public>) -> GenesisConfig { fn devnet_genesis(validators: &[&'static str], endowed_accounts: Vec<Public>) -> GenesisConfig {

View File

@@ -6,7 +6,7 @@ use sp_timestamp::InherentDataProvider as TimestampInherent;
use sp_consensus_babe::{SlotDuration, inherents::InherentDataProvider as BabeInherent}; use sp_consensus_babe::{SlotDuration, inherents::InherentDataProvider as BabeInherent};
use sp_io::SubstrateHostFunctions; use sp_io::SubstrateHostFunctions;
use sc_executor::{sp_wasm_interface::ExtendedHostFunctions, WasmExecutor}; use sc_executor::{sp_wasm_interface::ExtendedHostFunctions, HeapAllocStrategy, WasmExecutor};
use sc_network::{Event, NetworkEventStream, NetworkBackend}; use sc_network::{Event, NetworkEventStream, NetworkBackend};
use sc_service::{error::Error as ServiceError, Configuration, TaskManager, TFullClient}; use sc_service::{error::Error as ServiceError, Configuration, TaskManager, TFullClient};
@@ -99,14 +99,13 @@ pub fn new_partial(
}) })
.transpose()?; .transpose()?;
#[allow(deprecated)] let executor = Executor::builder()
let executor = Executor::new( .with_execution_method(config.executor.wasm_method)
config.executor.wasm_method, .with_onchain_heap_alloc_strategy(HeapAllocStrategy::Dynamic { maximum_pages: None })
config.executor.default_heap_pages, .with_offchain_heap_alloc_strategy(HeapAllocStrategy::Dynamic { maximum_pages: None })
config.executor.max_runtime_instances, .with_max_runtime_instances(config.executor.max_runtime_instances)
None, .with_runtime_cache_size(config.executor.runtime_cache_size)
config.executor.runtime_cache_size, .build();
);
let (client, backend, keystore_container, task_manager) = { let (client, backend, keystore_container, task_manager) = {
let telemetry = telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()); let telemetry = telemetry.as_ref().map(|(_, telemetry)| telemetry.handle());

View File

@@ -70,9 +70,6 @@ serai-dex-pallet = { path = "../dex", default-features = false }
serai-genesis-liquidity-pallet = { path = "../genesis-liquidity", default-features = false } serai-genesis-liquidity-pallet = { path = "../genesis-liquidity", default-features = false }
serai-in-instructions-pallet = { path = "../in-instructions", default-features = false } serai-in-instructions-pallet = { path = "../in-instructions", default-features = false }
[build-dependencies]
substrate-wasm-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk" }
[features] [features]
std = [ std = [
"scale/std", "scale/std",

View File

@@ -1,4 +1,101 @@
fn main() { fn main() {
#[cfg(not(target_family = "wasm"))] use std::{path::PathBuf, fs, env, process::Command};
substrate_wasm_builder::WasmBuilder::build_using_defaults();
// Prevent recursing infinitely
if env::var("TARGET").unwrap() == "wasm32v1-none" {
return;
}
// https://github.com/rust-lang/rust/issues/145491
const ONE_45491: &str = "-C link-arg=--mllvm=-mcpu=mvp,--mllvm=-mattr=+mutable-globals";
const WASM: &str = "-C link-arg=--export-table";
const REQUIRED_BY_SUBSTRATE: &str = "--cfg substrate_runtime";
const SAFETY: &str = "-C overflow-checks=true -C panic=abort";
// `symbol-mangling-version` is defined to provide an explicit, canonical definition of symbols.
// `embed-bitcode=false` is set as the bitcode is unnecessary yet takes notable time to compile.
/*
Rust's LTO requires bitcode, forcing us to defer to the linker's LTO. While this would suggest
we _should_ set `embed-bitcode=true`, Rust's documentation suggests that's likely not desired
and should solely be done when compiling one library with mixed methods of linking. When
compiling and linking just once (as seen here), it's suggested to use the linker's LTO instead.
https://doc.rust-lang.org/1.91.1/rustc/codegen-options/index.html#embed-bitcode
*/
const COMPILATION: &str =
"-C symbol-mangling-version=v0 -C embed-bitcode=false -C linker-plugin-lto=true";
let profile = env::var("PROFILE").unwrap();
let release = profile == "release";
let rustflags = format!("{ONE_45491} {WASM} {REQUIRED_BY_SUBSTRATE} {SAFETY} {COMPILATION}");
let rustflags = if release {
format!("{rustflags} -C codegen-units=1 -C strip=symbols -C debug-assertions=false")
} else {
rustflags
};
let target_dir = PathBuf::from(env::var("OUT_DIR").unwrap()).join("target");
let cargo_command = || {
let cargo = env::var("CARGO").unwrap();
let mut command = Command::new(&cargo);
command
.current_dir(env::var("CARGO_MANIFEST_DIR").unwrap())
.env_clear()
.env("PATH", env::var("PATH").unwrap())
.env("CARGO", cargo)
.env("RUSTC", env::var("RUSTC").unwrap())
.env("RUSTFLAGS", &rustflags)
.env("CARGO_TARGET_DIR", &target_dir);
command
};
let workspace = {
let workspace = cargo_command()
.arg("locate-project")
.arg("--workspace")
.arg("--message-format")
.arg("plain")
.output()
.unwrap();
assert!(workspace.status.success());
let mut workspace = PathBuf::from(String::from_utf8(workspace.stdout).unwrap().trim());
assert_eq!(workspace.file_name().unwrap(), "Cargo.toml");
assert!(workspace.pop());
workspace
};
// Re-run anytime the workspace changes
// TODO: Re-run anytime `Cargo.lock` or specifically the `src` folders change
println!("cargo::rerun-if-changed={}", workspace.display());
let mut command = cargo_command();
command
.arg("rustc")
.arg("--package")
.arg(env::var("CARGO_PKG_NAME").unwrap())
.arg("--target")
.arg("wasm32v1-none")
.arg("--crate-type")
.arg("cdylib")
.arg("--no-default-features");
if release {
command.arg("--release");
}
assert!(command.status().unwrap().success());
// Place the resulting WASM blob into the parent `target` directory
{
let wasm_file = env::var("CARGO_PKG_NAME").unwrap().replace('-', "_") + ".wasm";
let src_file = target_dir.join("wasm32v1-none").join(&profile).join(&wasm_file);
let dst_file = {
// TODO: This sets `dst_dir` to the default target directory, not the actual
let mut dst_dir = workspace.clone();
// e.g. workspace/target/debug
dst_dir.extend(["target", &profile]);
let _ = fs::create_dir_all(&dst_dir);
// e.g. workspace/target/debug/serai_runtime.wasm
dst_dir.join(&wasm_file)
};
fs::copy(&src_file, &dst_file).unwrap();
}
} }

View File

@@ -20,5 +20,9 @@ mod std_runtime_api;
pub use std_runtime_api::RuntimeApi; pub use std_runtime_api::RuntimeApi;
// If this isn't WASM, regardless of what it is, we include the WASM blob from the build script // If this isn't WASM, regardless of what it is, we include the WASM blob from the build script
#[cfg(not(target_family = "wasm"))] #[cfg(all(not(target_family = "wasm"), debug_assertions))]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub const WASM: &[u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/target/wasm32v1-none/debug/serai_runtime.wasm"));
#[cfg(all(not(target_family = "wasm"), not(debug_assertions)))]
pub const WASM: &[u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/target/wasm32v1-none/release/serai_runtime.wasm"));

View File

@@ -73,11 +73,10 @@ impl frame_system::Config for Runtime {
// We assume `serai-node` will be run using the RocksDB backend // We assume `serai-node` will be run using the RocksDB backend
type DbWeight = frame_support::weights::constants::RocksDbWeight; type DbWeight = frame_support::weights::constants::RocksDbWeight;
/* /*
Serai does not expose `frame_system::Call` nor does it use transaction extensions. We Serai does not expose `frame_system::Call`. We accordingly have no consequence to using the
accordingly have no consequence to using the default weights for these accordingly. default weights for these accordingly.
*/ */
type SystemWeightInfo = (); type SystemWeightInfo = ();
type ExtensionsWeightInfo = ();
// We also don't use `frame_system`'s account system at all, leaving us to bottom these out. // We also don't use `frame_system`'s account system at all, leaving us to bottom these out.
type AccountData = (); type AccountData = ();