use clap::Parser;
use colored::*;
use radix_common::prelude::*;
use radix_engine::blueprints::models::*;
use radix_engine::vm::wasm::ScryptoV1WasmValidator;
use radix_engine::vm::ScryptoVmVersion;
use radix_engine_interface::blueprints::package::{
BlueprintDefinition, BlueprintDependencies, BlueprintPayloadDef, FunctionSchema,
IndexedStateSchema, PackageExport, VmType, *,
};
use radix_engine_interface::prelude::*;
use radix_rust::ContextualDisplay;
use radix_substate_store_interface::db_key_mapper::*;
use radix_substate_store_interface::interface::*;
use radix_substate_store_queries::typed_substate_layout::*;
use std::ffi::OsStr;
use std::fs;
use std::path::PathBuf;
use crate::resim::*;
use crate::utils::*;
#[derive(Parser, Debug)]
pub struct Publish {
pub path: PathBuf,
#[clap(long)]
pub owner_badge: Option<SimulatorNonFungibleGlobalId>,
#[clap(long)]
pub package_address: Option<SimulatorPackageAddress>,
#[clap(short, long)]
pub network: Option<String>,
#[clap(short, long)]
pub manifest: Option<PathBuf>,
#[clap(short, long)]
pub trace: bool,
#[clap(long)]
disable_wasm_opt: bool,
#[clap(long)]
log_level: Option<Level>,
}
impl Publish {
pub fn run<O: std::io::Write>(&self, out: &mut O) -> Result<(), String> {
let (code_path, definition_path) = if self.path.extension() != Some(OsStr::new("wasm")) {
let build_artifacts = build_package(
&self.path,
self.disable_wasm_opt,
self.log_level.unwrap_or_default(),
false,
[],
)
.map_err(Error::BuildError)?;
if build_artifacts.len() > 1 {
return Err(Error::BuildError(BuildError::WorkspaceNotSupported).into());
} else {
build_artifacts
.first()
.ok_or(Error::BuildError(BuildError::BuildArtifactsEmpty))?
.to_owned()
}
} else {
let code_path = self.path.clone();
let schema_path = code_path.with_extension("rpd");
(code_path, schema_path)
};
let code = fs::read(code_path).map_err(Error::IOError)?;
let package_definition = manifest_decode::<ManifestPackageDefinition>(
&fs::read(&definition_path)
.map_err(|err| Error::IOErrorAtPath(err, definition_path))?,
)
.map_err(Error::SborDecodeError)?
.try_into_typed()
.map_err(Error::PackageDefinitionConversionError)?;
if let Some(package_address) = self.package_address.clone() {
let SimulatorEnvironment { mut db, .. } = SimulatorEnvironment::new()?;
let node_id: NodeId = package_address.0.into();
let code_hash = CodeHash::from(hash(&code));
let blueprints_partition_key = SpreadPrefixKeyMapper::to_db_partition_key(
&node_id,
MAIN_BASE_PARTITION
.at_offset(PACKAGE_BLUEPRINTS_PARTITION_OFFSET)
.unwrap(),
);
let schemas_partition_key =
SpreadPrefixKeyMapper::to_db_partition_key(&node_id, SCHEMAS_PARTITION);
let dependencies_partition_key = SpreadPrefixKeyMapper::to_db_partition_key(
&node_id,
MAIN_BASE_PARTITION
.at_offset(PACKAGE_BLUEPRINT_DEPENDENCIES_PARTITION_OFFSET)
.unwrap(),
);
let royalty_configs_partition_key = SpreadPrefixKeyMapper::to_db_partition_key(
&node_id,
MAIN_BASE_PARTITION
.at_offset(PACKAGE_ROYALTY_PARTITION_OFFSET)
.unwrap(),
);
let auth_configs_partition_key = SpreadPrefixKeyMapper::to_db_partition_key(
&node_id,
MAIN_BASE_PARTITION
.at_offset(PACKAGE_AUTH_TEMPLATE_PARTITION_OFFSET)
.unwrap(),
);
let vm_type_partition_key = SpreadPrefixKeyMapper::to_db_partition_key(
&node_id,
MAIN_BASE_PARTITION
.at_offset(PACKAGE_VM_TYPE_PARTITION_OFFSET)
.unwrap(),
);
let original_code_partition_key = SpreadPrefixKeyMapper::to_db_partition_key(
&node_id,
MAIN_BASE_PARTITION
.at_offset(PACKAGE_ORIGINAL_CODE_PARTITION_OFFSET)
.unwrap(),
);
let instrumented_code_partition_key = SpreadPrefixKeyMapper::to_db_partition_key(
&node_id,
MAIN_BASE_PARTITION
.at_offset(PACKAGE_INSTRUMENTED_CODE_PARTITION_OFFSET)
.unwrap(),
);
let mut blueprint_updates = index_map_new();
let mut dependency_updates = index_map_new();
let mut auth_config_updates = index_map_new();
let mut royalty_config_updates = index_map_new();
let mut schema_updates = index_map_new();
let mut vm_type_updates = index_map_new();
let mut original_code_updates = index_map_new();
let mut instrumented_code_updates = index_map_new();
let instrumented_code = ScryptoV1WasmValidator::new(ScryptoVmVersion::latest())
.validate(&code, package_definition.blueprints.values())
.map_err(Error::InvalidPackage)?
.0;
let vm_type = PackageCodeVmType {
vm_type: VmType::ScryptoV1,
};
let original_code = PackageCodeOriginalCode { code };
let instrumented_code = PackageCodeInstrumentedCode { instrumented_code };
{
let key =
SpreadPrefixKeyMapper::map_to_db_sort_key(&scrypto_encode(&code_hash).unwrap());
let update =
DatabaseUpdate::Set(scrypto_encode(&vm_type.into_locked_substate()).unwrap());
vm_type_updates.insert(key, update);
let key =
SpreadPrefixKeyMapper::map_to_db_sort_key(&scrypto_encode(&code_hash).unwrap());
let update = DatabaseUpdate::Set(
scrypto_encode(&original_code.into_locked_substate()).unwrap(),
);
original_code_updates.insert(key, update);
let key =
SpreadPrefixKeyMapper::map_to_db_sort_key(&scrypto_encode(&code_hash).unwrap());
let update = DatabaseUpdate::Set(
scrypto_encode(&instrumented_code.into_locked_substate()).unwrap(),
);
instrumented_code_updates.insert(key, update);
}
for (blueprint_name, blueprint_definition) in package_definition.blueprints {
let mut functions = index_map_new();
let mut function_exports = index_map_new();
let blueprint_version_key = BlueprintVersionKey::new_default(blueprint_name);
let blueprint_schema = blueprint_definition.schema.clone();
let schema_hash = blueprint_schema.schema.generate_schema_hash();
schema_updates.insert(
SpreadPrefixKeyMapper::map_to_db_sort_key(
&scrypto_encode(&schema_hash).unwrap(),
),
DatabaseUpdate::Set(
scrypto_encode(&blueprint_schema.schema.into_locked_substate()).unwrap(),
),
);
for (function, setup) in blueprint_definition.schema.functions.functions {
functions.insert(
function.clone(),
FunctionSchema {
receiver: setup.receiver,
input: BlueprintPayloadDef::from_type_ref(setup.input, schema_hash),
output: BlueprintPayloadDef::from_type_ref(setup.output, schema_hash),
},
);
let export = PackageExport {
code_hash,
export_name: setup.export.clone(),
};
function_exports.insert(function, export);
}
let events = blueprint_definition
.schema
.events
.event_schema
.into_iter()
.map(|(key, type_ref)| {
(
key,
BlueprintPayloadDef::from_type_ref(type_ref, schema_hash),
)
})
.collect();
let types = blueprint_definition
.schema
.types
.type_schema
.into_iter()
.map(|(key, local_type_id)| {
(
key,
ScopedTypeId(
blueprint_definition.schema.schema.generate_schema_hash(),
local_type_id,
),
)
})
.collect();
let state = IndexedStateSchema::from_schema(
schema_hash,
blueprint_definition.schema.state,
Default::default(),
);
let def = BlueprintDefinition {
interface: BlueprintInterface {
generics: blueprint_definition.schema.generics,
blueprint_type: blueprint_definition.blueprint_type,
is_transient: false,
feature_set: blueprint_definition.feature_set,
functions,
events,
state,
types,
},
function_exports,
hook_exports: index_map_new(),
};
blueprint_updates.insert(
SpreadPrefixKeyMapper::map_to_db_sort_key(
&scrypto_encode(&blueprint_version_key.clone()).unwrap(),
),
DatabaseUpdate::Set(scrypto_encode(&def.into_locked_substate()).unwrap()),
);
dependency_updates.insert(
SpreadPrefixKeyMapper::map_to_db_sort_key(
&scrypto_encode(&blueprint_version_key.clone()).unwrap(),
),
DatabaseUpdate::Set(
scrypto_encode(
&BlueprintDependencies {
dependencies: blueprint_definition.dependencies,
}
.into_locked_substate(),
)
.unwrap(),
),
);
auth_config_updates.insert(
SpreadPrefixKeyMapper::map_to_db_sort_key(
&scrypto_encode(&blueprint_version_key.clone()).unwrap(),
),
DatabaseUpdate::Set(
scrypto_encode(&blueprint_definition.auth_config.into_locked_substate())
.unwrap(),
),
);
royalty_config_updates.insert(
SpreadPrefixKeyMapper::map_to_db_sort_key(
&scrypto_encode(&blueprint_version_key.clone()).unwrap(),
),
DatabaseUpdate::Set(
scrypto_encode(&blueprint_definition.royalty_config.into_locked_substate())
.unwrap(),
),
);
}
let database_updates = indexmap!(
blueprints_partition_key => blueprint_updates,
dependencies_partition_key => dependency_updates,
auth_configs_partition_key => auth_config_updates,
royalty_configs_partition_key => royalty_config_updates,
schemas_partition_key => schema_updates,
vm_type_partition_key => vm_type_updates,
original_code_partition_key => original_code_updates,
instrumented_code_partition_key => instrumented_code_updates,
);
db.commit(&DatabaseUpdates::from_delta_maps(database_updates));
writeln!(out, "Package updated!").map_err(Error::IOError)?;
} else {
let owner_badge_non_fungible_global_id = self
.owner_badge
.clone()
.map(|owner_badge| owner_badge.0)
.unwrap_or(get_default_owner_badge()?);
let manifest = ManifestBuilder::new()
.lock_fee_from_faucet()
.publish_package_with_owner(
code,
package_definition,
owner_badge_non_fungible_global_id,
)
.build();
let receipt = handle_manifest(
manifest.into(),
&None,
&self.network,
&self.manifest,
self.trace,
false,
out,
)?;
if let Some(receipt) = receipt {
writeln!(
out,
"Success! New Package: {}",
receipt.expect_commit(true).new_package_addresses()[0]
.display(&AddressBech32Encoder::for_simulator())
.to_string()
.green()
)
.map_err(Error::IOError)?;
}
}
Ok(())
}
}