Use the deterministically built wasm

Has the Dockerfile output to a volume. Has the node use the wasm from the
volume, if it exists.
This commit is contained in:
Luke Parker 2024-03-22 02:19:09 -04:00
parent 84cee06ac1
commit fab7a0a7cb
No known key found for this signature in database
6 changed files with 117 additions and 18 deletions

View file

@ -1,17 +1,20 @@
FROM --platform=linux/amd64 rust:1.77.0-slim-bookworm as builder
# rust:1.77.0-slim-bookworm as of March 22nd, 2024 (GMT)
FROM --platform=linux/amd64 rust@sha256:e785e4aa81f87bc1ee02fa2026ffbc491e0410bdaf6652cea74884373f452664 as deterministic
# Move to a Debian package snapshot
RUN rm -rf /etc/apt/sources.list.d/debian.sources && \
rm -rf /var/lib/apt/lists/* && \
echo "deb [arch=amd64] http://snapshot.debian.org/archive/debian/20240201T000000Z bookworm main" > /etc/apt/sources.list && \
echo "deb [arch=amd64] http://snapshot.debian.org/archive/debian/20240301T000000Z bookworm main" > /etc/apt/sources.list && \
apt update
# Install dependencies
RUN apt install clang -y
RUN apt update && apt upgrade && apt install clang -y
# Add the wasm toolchain
RUN rustup target add wasm32-unknown-unknown
FROM deterministic
# Add files for build
ADD patches /serai/patches
ADD common /serai/common
@ -30,3 +33,8 @@ ADD Cargo.lock /serai
ADD AGPL-3.0 /serai
WORKDIR /serai
# Build the runtime, copying it to the volume if it exists
CMD cargo build --release -p serai-runtime && \
mkdir -p /volume && \
cp /serai/target/release/wbuild/serai-runtime/serai_runtime.wasm /volume/serai.wasm

View file

@ -325,6 +325,87 @@ fn start(network: Network, services: HashSet<String>) {
_ => panic!("starting unrecognized service"),
};
// If we're building the Serai service, first build the runtime
let serai_runtime_volume = format!("serai-{}-runtime-volume", network.label());
if name == "serai" {
// Check if it's built by checking if the volume has the expected runtime file
let built = || {
if let Ok(path) = Command::new("docker")
.arg("volume")
.arg("inspect")
.arg("-f")
.arg("{{ .Mountpoint }}")
.arg(&serai_runtime_volume)
.output()
{
if let Ok(path) = String::from_utf8(path.stdout) {
if let Ok(iter) = std::fs::read_dir(PathBuf::from(path.trim())) {
for item in iter.flatten() {
if item.file_name() == "serai.wasm" {
return true;
}
}
}
}
}
false
};
if !built() {
let mut repo_path = env::current_exe().unwrap();
repo_path.pop();
if repo_path.as_path().ends_with("deps") {
repo_path.pop();
}
assert!(repo_path.as_path().ends_with("debug") || repo_path.as_path().ends_with("release"));
repo_path.pop();
assert!(repo_path.as_path().ends_with("target"));
repo_path.pop();
// Build the image to build the runtime
if !Command::new("docker")
.current_dir(&repo_path)
.arg("build")
.arg("-f")
.arg("orchestration/runtime/Dockerfile")
.arg(".")
.arg("-t")
.arg(format!("serai-{}-runtime-img", network.label()))
.spawn()
.unwrap()
.wait()
.unwrap()
.success()
{
panic!("failed to build runtime image");
}
// Run the image, building the runtime
println!("Building the Serai runtime");
let container_name = format!("serai-{}-runtime", network.label());
let _ =
Command::new("docker").arg("rm").arg("-f").arg(&container_name).spawn().unwrap().wait();
let _ = Command::new("docker")
.arg("run")
.arg("--name")
.arg(container_name)
.arg("--volume")
.arg(format!("{serai_runtime_volume}:/volume"))
.arg(format!("serai-{}-runtime-img", network.label()))
.spawn();
// Wait until its built
let mut ticks = 0;
while !built() {
std::thread::sleep(core::time::Duration::from_secs(60));
ticks += 1;
if ticks > 6 * 60 {
panic!("couldn't build the runtime after 6 hours")
}
}
}
}
// Build it
println!("Building {service}");
docker::build(&orchestration_path(network), network, name);
@ -367,6 +448,7 @@ fn start(network: Network, services: HashSet<String>) {
assert_eq!(network, Network::Dev, "monero-wallet-rpc is only for dev");
command.arg("-p").arg("18082:18082")
}
"serai" => command.arg("--volume").arg(format!("{serai_runtime_volume}:/runtime")),
_ => command,
};
assert!(

View file

@ -21,7 +21,7 @@ EXPOSE 30333 9615 9933 9944
ADD /orchestration/{}/serai/run.sh /
CMD ["/run.sh"]
"#,
network.label()
network.label(),
);
let run = os(Os::Debian, "", "serai") + &run_serai;

View file

@ -15,6 +15,14 @@ fn account_from_name(name: &'static str) -> PublicKey {
insecure_pair_from_name(name).public()
}
fn wasm_binary() -> Vec<u8> {
// TODO: Accept a config of runtime path
if let Ok(binary) = std::fs::read("/runtime/serai.wasm") {
return binary;
}
WASM_BINARY.ok_or("compiled in wasm not available").unwrap().to_vec()
}
fn testnet_genesis(
wasm_binary: &[u8],
validators: &[&'static str],
@ -64,18 +72,18 @@ fn testnet_genesis(
}
}
pub fn development_config() -> Result<ChainSpec, &'static str> {
let wasm_binary = WASM_BINARY.ok_or("Development wasm not available")?;
pub fn development_config() -> ChainSpec {
let wasm_binary = wasm_binary();
Ok(ChainSpec::from_genesis(
ChainSpec::from_genesis(
// Name
"Development Network",
// ID
"devnet",
ChainType::Development,
|| {
move || {
testnet_genesis(
wasm_binary,
&wasm_binary,
&["Alice"],
vec![
account_from_name("Alice"),
@ -99,21 +107,21 @@ pub fn development_config() -> Result<ChainSpec, &'static str> {
None,
// Extensions
None,
))
)
}
pub fn testnet_config() -> Result<ChainSpec, &'static str> {
let wasm_binary = WASM_BINARY.ok_or("Testnet wasm not available")?;
pub fn testnet_config() -> ChainSpec {
let wasm_binary = wasm_binary();
Ok(ChainSpec::from_genesis(
ChainSpec::from_genesis(
// Name
"Local Test Network",
// ID
"local",
ChainType::Local,
|| {
move || {
testnet_genesis(
wasm_binary,
&wasm_binary,
&["Alice", "Bob", "Charlie", "Dave"],
vec![
account_from_name("Alice"),
@ -137,5 +145,5 @@ pub fn testnet_config() -> Result<ChainSpec, &'static str> {
None,
// Extensions
None,
))
)
}

View file

@ -39,8 +39,8 @@ impl SubstrateCli for Cli {
fn load_spec(&self, id: &str) -> Result<Box<dyn sc_service::ChainSpec>, String> {
match id {
"dev" | "devnet" => Ok(Box::new(chain_spec::development_config()?)),
"local" => Ok(Box::new(chain_spec::testnet_config()?)),
"dev" | "devnet" => Ok(Box::new(chain_spec::development_config())),
"local" => Ok(Box::new(chain_spec::testnet_config())),
_ => panic!("Unknown network ID"),
}
}

View file

@ -142,6 +142,7 @@ pub mod pallet {
}
// 80% threshold
// TODO: Use 34% for halting a set (not 80%)
const REQUIREMENT_NUMERATOR: u64 = 4;
const REQUIREMENT_DIVISOR: u64 = 5;