diff --git a/Cargo.lock b/Cargo.lock index 6de49f98..2642edfd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -829,6 +829,7 @@ dependencies = [ name = "header-verifier" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "multiversx-sc-scenario", "num-bigint", diff --git a/chain-factory/src/factory.rs b/chain-factory/src/factory.rs index 6d8cdd29..0d9918c0 100644 --- a/chain-factory/src/factory.rs +++ b/chain-factory/src/factory.rs @@ -37,6 +37,7 @@ pub trait FactoryModule: only_admin::OnlyAdminModule { #[endpoint(deployHeaderVerifier)] fn deploy_header_verifier( &self, + chain_config_address: ManagedAddress, bls_pub_keys: MultiValueEncoded, ) -> ManagedAddress { let source_address = self.header_verifier_template().get(); @@ -44,7 +45,7 @@ pub trait FactoryModule: only_admin::OnlyAdminModule { self.tx() .typed(HeaderverifierProxy) - .init(bls_pub_keys) + .init(chain_config_address, bls_pub_keys) .gas(60_000_000) .from_source(source_address) .code_metadata(metadata) diff --git a/common/operation/src/lib.rs b/common/operation/src/lib.rs index 153bf9be..438e3d20 100644 --- a/common/operation/src/lib.rs +++ b/common/operation/src/lib.rs @@ -12,7 +12,9 @@ pub const MIN_BLOCKS_FOR_FINALITY: u64 = 10; const DEFAULT_MAX_TX_GAS_LIMIT: u64 = 300_000_000; #[type_abi] -#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem, Clone)] +#[derive( + TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem, Clone, Debug, PartialEq, +)] pub struct StakeArgs { pub token_id: TokenIdentifier, pub amount: BigUint, @@ -25,7 +27,9 @@ impl StakeArgs { } #[type_abi] -#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem, Clone)] +#[derive( + TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem, Clone, Debug, PartialEq, +)] pub struct SovereignConfig { pub min_validators: u64, pub max_validators: u64, diff --git a/common/proxies/src/chain_factory_proxy.rs b/common/proxies/src/chain_factory_proxy.rs index a9d8f482..b67a5fce 100644 --- a/common/proxies/src/chain_factory_proxy.rs +++ b/common/proxies/src/chain_factory_proxy.rs @@ -111,14 +111,17 @@ where } pub fn deploy_header_verifier< - Arg0: ProxyArg>>, + Arg0: ProxyArg>, + Arg1: ProxyArg>>, >( self, - bls_pub_keys: Arg0, + chain_config_address: Arg0, + bls_pub_keys: Arg1, ) -> TxTypedCall> { self.wrapped_tx .payment(NotPayable) .raw_call("deployHeaderVerifier") + .argument(&chain_config_address) .argument(&bls_pub_keys) .original_result() } diff --git a/common/proxies/src/header_verifier_proxy.rs b/common/proxies/src/header_verifier_proxy.rs index 01a7b046..ffa499dc 100644 --- a/common/proxies/src/header_verifier_proxy.rs +++ b/common/proxies/src/header_verifier_proxy.rs @@ -44,14 +44,17 @@ where Gas: TxGas, { pub fn init< - Arg0: ProxyArg>>, + Arg0: ProxyArg>, + Arg1: ProxyArg>>, >( self, - bls_pub_keys: Arg0, + chain_config_address: Arg0, + bls_pub_keys: Arg1, ) -> TxTypedDeploy { self.wrapped_tx .payment(NotPayable) .raw_deploy() + .argument(&chain_config_address) .argument(&bls_pub_keys) .original_result() } @@ -149,6 +152,32 @@ where .original_result() } + pub fn change_validator_set< + Arg0: ProxyArg>>, + >( + self, + bls_pub_keys: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("changeValidatorSet") + .argument(&bls_pub_keys) + .original_result() + } + + pub fn update_config< + Arg0: ProxyArg>, + >( + self, + new_config: Arg0, + ) -> TxTypedCall { + self.wrapped_tx + .payment(NotPayable) + .raw_call("updateConfig") + .argument(&new_config) + .original_result() + } + pub fn complete_setup_phase( self, ) -> TxTypedCall { diff --git a/enshrine-esdt-safe/interactor/src/enshrine_esdt_safe_interactor.rs b/enshrine-esdt-safe/interactor/src/enshrine_esdt_safe_interactor.rs index a93c678f..68401e53 100644 --- a/enshrine-esdt-safe/interactor/src/enshrine_esdt_safe_interactor.rs +++ b/enshrine-esdt-safe/interactor/src/enshrine_esdt_safe_interactor.rs @@ -132,6 +132,7 @@ impl ContractInteract { let mut bls_pub_keys = MultiValueEncoded::new(); bls_pub_keys.push(bls_pub_key); let header_verifier_code_path = MxscPath::new(&self.header_verifier_code); + let chain_config_address = Bech32Address::from_bech32_string("chain_config".to_string()); let new_address = self .interactor @@ -139,7 +140,7 @@ impl ContractInteract { .from(&self.wallet_address) .gas(100_000_000u64) .typed(header_verifier_proxy::HeaderverifierProxy) - .init(bls_pub_keys) + .init(chain_config_address, bls_pub_keys) .code(header_verifier_code_path) .returns(ReturnsNewAddress) .run() diff --git a/enshrine-esdt-safe/tests/enshrine_esdt_safe_blackbox_test.rs b/enshrine-esdt-safe/tests/enshrine_esdt_safe_blackbox_test.rs index 523f0155..e380e53b 100644 --- a/enshrine-esdt-safe/tests/enshrine_esdt_safe_blackbox_test.rs +++ b/enshrine-esdt-safe/tests/enshrine_esdt_safe_blackbox_test.rs @@ -34,6 +34,8 @@ const TOKEN_HANDLER_CODE_PATH: MxscPath = const FEE_MARKET_ADDRESS: TestSCAddress = TestSCAddress::new("fee-market"); const FEE_MARKET_CODE_PATH: MxscPath = MxscPath::new("../fee-market/output/fee-market.mxsc.json"); +const CHAIN_CONFIG_ADDRESS: TestSCAddress = TestSCAddress::new("chain-config"); + const USER_ADDRESS: TestAddress = TestAddress::new("user"); const INSUFFICIENT_WEGLD_ADDRESS: TestAddress = TestAddress::new("insufficient_wegld"); const RECEIVER_ADDRESS: TestAddress = TestAddress::new("receiver"); @@ -169,7 +171,7 @@ impl EnshrineTestState { .tx() .from(ENSHRINE_ESDT_OWNER_ADDRESS) .typed(HeaderverifierProxy) - .init(bls_pub_keys) + .init(CHAIN_CONFIG_ADDRESS, bls_pub_keys) .code(HEADER_VERIFIER_CODE_PATH) .new_address(HEADER_VERIFIER_ADDRESS) .run(); diff --git a/enshrine-esdt-safe/wasm-enshrine-esdt-safe-full/Cargo.lock b/enshrine-esdt-safe/wasm-enshrine-esdt-safe-full/Cargo.lock index 545730e1..b2c084b4 100644 --- a/enshrine-esdt-safe/wasm-enshrine-esdt-safe-full/Cargo.lock +++ b/enshrine-esdt-safe/wasm-enshrine-esdt-safe-full/Cargo.lock @@ -90,6 +90,7 @@ dependencies = [ name = "header-verifier" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "operation", "proxies", diff --git a/enshrine-esdt-safe/wasm-enshrine-esdt-safe-view/Cargo.lock b/enshrine-esdt-safe/wasm-enshrine-esdt-safe-view/Cargo.lock index 7a25627e..33f0519c 100644 --- a/enshrine-esdt-safe/wasm-enshrine-esdt-safe-view/Cargo.lock +++ b/enshrine-esdt-safe/wasm-enshrine-esdt-safe-view/Cargo.lock @@ -90,6 +90,7 @@ dependencies = [ name = "header-verifier" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "operation", "proxies", diff --git a/enshrine-esdt-safe/wasm/Cargo.lock b/enshrine-esdt-safe/wasm/Cargo.lock index d5a2e784..ccb7d59b 100644 --- a/enshrine-esdt-safe/wasm/Cargo.lock +++ b/enshrine-esdt-safe/wasm/Cargo.lock @@ -90,6 +90,7 @@ dependencies = [ name = "header-verifier" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "operation", "proxies", diff --git a/esdt-safe/interactor/src/esdt_safe_interactor.rs b/esdt-safe/interactor/src/esdt_safe_interactor.rs index 43581c90..0a04ae60 100644 --- a/esdt-safe/interactor/src/esdt_safe_interactor.rs +++ b/esdt-safe/interactor/src/esdt_safe_interactor.rs @@ -8,13 +8,13 @@ use multiversx_sc_scenario::multiversx_chain_vm::crypto_functions::{sha256, SHA2 use multiversx_sc_scenario::scenario_model::TxResponseStatus; use multiversx_sc_snippets::imports::*; use multiversx_sc_snippets::sdk::{self}; +use operation::aliases::{OptionalTransferData, PaymentsVec}; +use operation::{Operation, OperationData}; +use operation::{OperationEsdtPayment, TransferData}; use proxies::esdt_safe_proxy::EsdtSafeProxy; use proxies::fee_market_proxy::{FeeMarketProxy, FeeStruct, FeeType}; use proxies::header_verifier_proxy::HeaderverifierProxy; use proxies::testing_sc_proxy::TestingScProxy; -use operation::aliases::{OptionalTransferData, PaymentsVec}; -use operation::{Operation, OperationData}; -use operation::{OperationEsdtPayment, TransferData}; const FEE_MARKET_CODE_PATH: &str = "../../fee-market/output/fee-market.mxsc.json"; const HEADER_VERIFIER_CODE_PATH: &str = "../../header-verifier/output/header-verifier.mxsc.json"; @@ -151,6 +151,7 @@ impl ContractInteract { pub async fn deploy_header_verifier_contract(&mut self) { let header_verifier_code_path = MxscPath::new(&self.header_verifier_code); + let chain_config_address = Bech32Address::from_bech32_string("chain_config".to_string()); let new_address = self .interactor @@ -158,7 +159,7 @@ impl ContractInteract { .from(&self.wallet_address) .gas(100_000_000u64) .typed(HeaderverifierProxy) - .init(MultiValueEncoded::new()) + .init(chain_config_address, MultiValueEncoded::new()) .code(header_verifier_code_path) .returns(ReturnsNewAddress) .run() diff --git a/esdt-safe/tests/bridge_blackbox_tests.rs b/esdt-safe/tests/bridge_blackbox_tests.rs index f5d8d287..28c04e01 100644 --- a/esdt-safe/tests/bridge_blackbox_tests.rs +++ b/esdt-safe/tests/bridge_blackbox_tests.rs @@ -11,10 +11,10 @@ use multiversx_sc_scenario::multiversx_chain_vm::crypto_functions::sha256; use multiversx_sc_scenario::{ api::StaticApi, imports::MxscPath, ExpectError, ScenarioTxRun, ScenarioWorld, }; +use operation::{Operation, OperationData, OperationEsdtPayment}; use proxies::esdt_safe_proxy::EsdtSafeProxy; use proxies::fee_market_proxy::{FeeMarketProxy, FeeStruct, FeeType}; use proxies::header_verifier_proxy::HeaderverifierProxy; -use operation::{Operation, OperationData, OperationEsdtPayment}; const BRIDGE_ADDRESS: TestSCAddress = TestSCAddress::new("bridge"); const BRIDGE_CODE_PATH: MxscPath = MxscPath::new("output/esdt-safe.mxsc.json"); @@ -27,6 +27,8 @@ const HEADER_VERIFIER_ADDRESS: TestSCAddress = TestSCAddress::new("header_verifi const HEADER_VERIFIER_CODE_PATH: MxscPath = MxscPath::new("../header-verifier/output/header-verifier.mxsc.json"); +const CHAIN_CONFIG_ADDRESS: TestSCAddress = TestSCAddress::new("chain-config"); + const USER_ADDRESS: TestAddress = TestAddress::new("user"); const RECEIVER_ADDRESS: TestAddress = TestAddress::new("receiver"); @@ -114,7 +116,7 @@ impl BridgeTestState { .tx() .from(BRIDGE_OWNER_ADDRESS) .typed(HeaderverifierProxy) - .init(bls_pub_keys) + .init(CHAIN_CONFIG_ADDRESS, bls_pub_keys) .code(HEADER_VERIFIER_CODE_PATH) .new_address(HEADER_VERIFIER_ADDRESS) .run(); diff --git a/esdt-safe/wasm-esdt-safe-full/Cargo.lock b/esdt-safe/wasm-esdt-safe-full/Cargo.lock index a892a1e5..41779611 100644 --- a/esdt-safe/wasm-esdt-safe-full/Cargo.lock +++ b/esdt-safe/wasm-esdt-safe-full/Cargo.lock @@ -20,6 +20,17 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "chain-config" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", + "operation", + "proxies", + "setup-phase", +] + [[package]] name = "endian-type" version = "0.1.2" @@ -66,6 +77,7 @@ dependencies = [ name = "header-verifier" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "operation", "proxies", diff --git a/esdt-safe/wasm-esdt-safe-view/Cargo.lock b/esdt-safe/wasm-esdt-safe-view/Cargo.lock index d4617fb5..45f390ab 100644 --- a/esdt-safe/wasm-esdt-safe-view/Cargo.lock +++ b/esdt-safe/wasm-esdt-safe-view/Cargo.lock @@ -20,6 +20,17 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "chain-config" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", + "operation", + "proxies", + "setup-phase", +] + [[package]] name = "endian-type" version = "0.1.2" @@ -66,6 +77,7 @@ dependencies = [ name = "header-verifier" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "operation", "proxies", diff --git a/esdt-safe/wasm/Cargo.lock b/esdt-safe/wasm/Cargo.lock index 0f002261..173d51de 100644 --- a/esdt-safe/wasm/Cargo.lock +++ b/esdt-safe/wasm/Cargo.lock @@ -20,6 +20,17 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "chain-config" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", + "operation", + "proxies", + "setup-phase", +] + [[package]] name = "endian-type" version = "0.1.2" @@ -66,6 +77,7 @@ dependencies = [ name = "header-verifier" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "operation", "proxies", diff --git a/header-verifier/Cargo.toml b/header-verifier/Cargo.toml index c498cf08..61cec049 100644 --- a/header-verifier/Cargo.toml +++ b/header-verifier/Cargo.toml @@ -11,6 +11,9 @@ path = "src/lib.rs" [dependencies.multiversx-sc] version = "=0.55.0" +[dependencies.chain-config] +path = "../chain-config" + [dependencies.operation] path = "../common/operation" diff --git a/header-verifier/src/lib.rs b/header-verifier/src/lib.rs index 607dd4d8..017ca0a6 100644 --- a/header-verifier/src/lib.rs +++ b/header-verifier/src/lib.rs @@ -2,6 +2,8 @@ use multiversx_sc::codec; use multiversx_sc::proxy_imports::{TopDecode, TopEncode}; +use operation::SovereignConfig; +use proxies::chain_config_proxy::ChainConfigContractProxy; multiversx_sc::imports!(); @@ -14,7 +16,18 @@ pub enum OperationHashStatus { #[multiversx_sc::contract] pub trait Headerverifier: setup_phase::SetupPhaseModule { #[init] - fn init(&self, bls_pub_keys: MultiValueEncoded) { + fn init( + &self, + chain_config_address: ManagedAddress, + bls_pub_keys: MultiValueEncoded, + ) { + require!( + self.blockchain().is_smart_contract(&chain_config_address), + "The given address is not a Smart Contract address" + ); + + self.chain_config_address().set(chain_config_address); + for pub_key in bls_pub_keys { self.bls_pub_keys().insert(pub_key); } @@ -90,6 +103,28 @@ pub trait Headerverifier: setup_phase::SetupPhaseModule { } } + #[endpoint(changeValidatorSet)] + fn change_validator_set(&self, bls_pub_keys: MultiValueEncoded) { + // TODO: verify signature + + self.check_validator_range(bls_pub_keys.len() as u64); + + self.bls_pub_keys().clear(); + self.bls_pub_keys().extend(bls_pub_keys); + // TODO: add event + } + + #[endpoint(updateConfig)] + fn update_config(&self, new_config: SovereignConfig) { + // TODO: verify signature + + self.tx() + .to(self.chain_config_address().get()) + .typed(ChainConfigContractProxy) + .update_config(new_config) + .sync_call(); + } + #[only_owner] #[endpoint(completeSetupPhase)] fn complete_setup_phase(&self) { @@ -97,23 +132,20 @@ pub trait Headerverifier: setup_phase::SetupPhaseModule { return; } - let chain_config_mapper = self.chain_config_address(); require!( - !chain_config_mapper.is_empty(), + !self.chain_config_address().is_empty(), "The Chain-Config address is not set" ); - let chain_config_address = chain_config_mapper.get(); - let min_validators = self.min_validators(chain_config_address).get(); - let number_of_validators = self.bls_pub_keys().len() as u32; + self.check_validator_range(self.bls_pub_keys().len() as u64); - require!( - number_of_validators > min_validators, - "There should be at least {} more validators so the setup phase can be completed", - (number_of_validators - min_validators) - ); + // TODO: + // self.tx() + // .to(ToSelf) + // .typed(UserBuiltinProxy) + // .change_owner_address() + // .sync_call(); - // change ownership self.setup_phase_complete().set(true); } @@ -151,6 +183,18 @@ pub trait Headerverifier: setup_phase::SetupPhaseModule { ); } + fn check_validator_range(&self, number_of_validators: u64) { + let sovereign_config = self + .sovereign_config(self.chain_config_address().get()) + .get(); + + require!( + number_of_validators >= sovereign_config.min_validators + && number_of_validators <= sovereign_config.max_validators, + "The current validator set lenght doesn't meet the Sovereign's requirements" + ); + } + // TODO fn verify_bls( &self, @@ -186,6 +230,9 @@ pub trait Headerverifier: setup_phase::SetupPhaseModule { #[storage_mapper("chainConfigAddress")] fn chain_config_address(&self) -> SingleValueMapper; - #[storage_mapper_from_address("minValidators")] - fn min_validators(&self, sc_address: ManagedAddress) -> SingleValueMapper; + #[storage_mapper_from_address("sovereignConfig")] + fn sovereign_config( + &self, + sc_address: ManagedAddress, + ) -> SingleValueMapper, ManagedAddress>; } diff --git a/header-verifier/tests/header_verifier_blackbox_test.rs b/header-verifier/tests/header_verifier_blackbox_test.rs index 8429e986..f5714456 100644 --- a/header-verifier/tests/header_verifier_blackbox_test.rs +++ b/header-verifier/tests/header_verifier_blackbox_test.rs @@ -1,3 +1,4 @@ +use chain_config::validator_rules::ValidatorRulesModule; use header_verifier::{Headerverifier, OperationHashStatus}; use multiversx_sc::types::ManagedBuffer; use multiversx_sc::{ @@ -9,13 +10,20 @@ use multiversx_sc_scenario::{ api::StaticApi, imports::MxscPath, multiversx_chain_vm::crypto_functions::sha256, DebugApi, ScenarioTxRun, ScenarioTxWhitebox, ScenarioWorld, }; +use operation::SovereignConfig; +use proxies::chain_config_proxy::ChainConfigContractProxy; use proxies::header_verifier_proxy::HeaderverifierProxy; const HEADER_VERIFIER_CODE_PATH: MxscPath = MxscPath::new("ouput/header-verifier.mxsc-json"); const HEADER_VERIFIER_ADDRESS: TestSCAddress = TestSCAddress::new("header-verifier"); +const CHAIN_CONFIG_CODE_PATH: MxscPath = + MxscPath::new("../chain-config/output/chain-config.mxsc-json"); +const CHAIN_CONFIG_ADDRESS: TestSCAddress = TestSCAddress::new("chain-config"); + // NOTE: This is a mock path const ENSHRINE_ADDRESS: TestAddress = TestAddress::new("enshrine"); +const DUMMY_SC_ADDRESS: TestSCAddress = TestSCAddress::new("dummy-sc"); const OWNER: TestAddress = TestAddress::new("owner"); const WEGLD_BALANCE: u128 = 100_000_000_000_000_000; @@ -31,7 +39,9 @@ pub struct BridgeOperation { fn world() -> ScenarioWorld { let mut blockchain = ScenarioWorld::new(); + blockchain.register_contract(HEADER_VERIFIER_CODE_PATH, header_verifier::ContractBuilder); + blockchain.register_contract(CHAIN_CONFIG_CODE_PATH, chain_config::ContractBuilder); blockchain } @@ -57,12 +67,16 @@ impl HeaderVerifierTestState { Self { world } } - fn deploy_header_verifier_contract(&mut self, bls_keys: BlsKeys) -> &mut Self { + fn deploy_header_verifier_contract( + &mut self, + chain_config_address: TestSCAddress, + bls_keys: BlsKeys, + ) -> &mut Self { self.world .tx() .from(OWNER) .typed(HeaderverifierProxy) - .init(bls_keys) + .init(chain_config_address, bls_keys) .code(HEADER_VERIFIER_CODE_PATH) .new_address(HEADER_VERIFIER_ADDRESS) .run(); @@ -70,6 +84,23 @@ impl HeaderVerifierTestState { self } + fn deploy_chain_config( + &mut self, + sovereign_config: &SovereignConfig, + admin: TestSCAddress, + ) -> &mut Self { + self.world + .tx() + .from(OWNER) + .typed(ChainConfigContractProxy) + .init(sovereign_config, admin) + .code(CHAIN_CONFIG_CODE_PATH) + .new_address(CHAIN_CONFIG_ADDRESS) + .run(); + + self + } + fn propose_register_esdt_address(&mut self, esdt_address: TestAddress) { self.world .tx() @@ -138,6 +169,42 @@ impl HeaderVerifierTestState { } } + fn update_config( + &mut self, + new_config: SovereignConfig, + error_message: Option<&str>, + ) { + let response = self + .world + .tx() + .from(OWNER) + .to(HEADER_VERIFIER_ADDRESS) + .typed(HeaderverifierProxy) + .update_config(new_config) + .returns(ReturnsHandledOrError::new()) + .run(); + + if let Err(error) = response { + assert_eq!(error_message, Some(error.message.as_str())) + } + } + + fn change_validator_set(&mut self, bls_keys: BlsKeys, error_message: Option<&str>) { + let response = self + .world + .tx() + .from(OWNER) + .to(HEADER_VERIFIER_ADDRESS) + .typed(HeaderverifierProxy) + .change_validator_set(bls_keys) + .returns(ReturnsHandledOrError::new()) + .run(); + + if let Err(error) = response { + assert_eq!(error_message, Some(error.message.as_str())) + } + } + fn get_bls_keys(&mut self, bls_keys_vec: Vec>) -> BlsKeys { let bls_keys = bls_keys_vec.iter().cloned().collect(); @@ -192,7 +259,7 @@ fn test_deploy() { let bls_key_1 = ManagedBuffer::from("bls_key_1"); let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); - state.deploy_header_verifier_contract(managed_bls_keys); + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); } #[test] @@ -201,7 +268,8 @@ fn test_register_esdt_address() { let bls_key_1 = ManagedBuffer::from("bls_key_1"); let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); - state.deploy_header_verifier_contract(managed_bls_keys); + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); + state.propose_register_esdt_address(ENSHRINE_ADDRESS); state @@ -221,7 +289,7 @@ fn test_register_bridge_operation() { let bls_key_1 = ManagedBuffer::from("bls_key_1"); let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); - state.deploy_header_verifier_contract(managed_bls_keys); + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); let operation_1 = ManagedBuffer::from("operation_1"); let operation_2 = ManagedBuffer::from("operation_2"); @@ -262,7 +330,7 @@ fn test_remove_executed_hash_caller_not_esdt_address() { let bls_key_1 = ManagedBuffer::from("bls_key_1"); let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); - state.deploy_header_verifier_contract(managed_bls_keys); + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); let operation_1 = ManagedBuffer::from("operation_1"); let operation_2 = ManagedBuffer::from("operation_2"); @@ -284,7 +352,7 @@ fn test_remove_executed_hash_no_esdt_address_registered() { let bls_key_1 = ManagedBuffer::from("bls_key_1"); let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); - state.deploy_header_verifier_contract(managed_bls_keys); + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); let operation_1 = ManagedBuffer::from("operation_1"); let operation_2 = ManagedBuffer::from("operation_2"); @@ -305,7 +373,7 @@ fn test_remove_one_executed_hash() { let bls_key_1 = ManagedBuffer::from("bls_key_1"); let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); - state.deploy_header_verifier_contract(managed_bls_keys); + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); let operation_hash_1 = ManagedBuffer::from("operation_1"); let operation_hash_2 = ManagedBuffer::from("operation_2"); @@ -348,7 +416,7 @@ fn test_remove_all_executed_hashes() { let bls_key_1 = ManagedBuffer::from("bls_key_1"); let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); - state.deploy_header_verifier_contract(managed_bls_keys); + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); let operation_1 = ManagedBuffer::from("operation_1"); let operation_2 = ManagedBuffer::from("operation_2"); @@ -395,7 +463,7 @@ fn test_lock_operation_not_registered() { let bls_key_1 = ManagedBuffer::from("bls_key_1"); let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); - state.deploy_header_verifier_contract(managed_bls_keys); + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); state.propose_register_esdt_address(ENSHRINE_ADDRESS); let operation_1 = ManagedBuffer::from("operation_1"); @@ -416,7 +484,7 @@ fn test_lock_operation() { let bls_key_1 = ManagedBuffer::from("bls_key_1"); let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); - state.deploy_header_verifier_contract(managed_bls_keys); + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); state.propose_register_esdt_address(ENSHRINE_ADDRESS); let operation_1 = ManagedBuffer::from("operation_1"); @@ -452,3 +520,118 @@ fn test_lock_operation() { assert!(is_hash_2_locked == OperationHashStatus::NotLocked); }) } + +#[test] +fn update_config_can_only_be_called_by_chain_config_admin() { + let mut state = HeaderVerifierTestState::new(); + let bls_key_1 = ManagedBuffer::from("bls_key_1"); + let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); + + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); + + let sovereign_config = SovereignConfig::new(0, 0, BigUint::default(), None); + + state.deploy_chain_config(&sovereign_config, DUMMY_SC_ADDRESS); + state.update_config( + sovereign_config, + Some("Endpoint can only be called by admins"), + ); +} + +#[test] +fn update_config_wrong_validator_range() { + let mut state = HeaderVerifierTestState::new(); + let bls_key_1 = ManagedBuffer::from("bls_key_1"); + let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); + + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); + + let sovereign_config = SovereignConfig::new(0, 0, BigUint::default(), None); + + state.deploy_chain_config(&sovereign_config, HEADER_VERIFIER_ADDRESS); + + let new_config = SovereignConfig::new(1, 0, BigUint::default(), None); + state.update_config(new_config, Some("Invalid min/max validator numbers")); +} + +#[test] +fn update_config() { + let mut state = HeaderVerifierTestState::new(); + let bls_key_1 = ManagedBuffer::from("bls_key_1"); + let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); + + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); + + let sovereign_config = SovereignConfig::new(0, 0, BigUint::default(), None); + + state.deploy_chain_config(&sovereign_config, HEADER_VERIFIER_ADDRESS); + state.update_config(sovereign_config, None); + + state + .world + .query() + .to(CHAIN_CONFIG_ADDRESS) + .whitebox(chain_config::contract_obj, |sc| { + let sovereign_config_mapper = sc.sovereign_config(); + + assert!(!sovereign_config_mapper.is_empty()); + let sovereign_config: SovereignConfig = + SovereignConfig::new(0, 0, BigUint::default(), None); + + let stored_sovereign_config = sovereign_config_mapper.get(); + + assert!(sovereign_config == stored_sovereign_config); + }) +} + +#[test] +fn change_validator_set_incorect_length() { + let mut state = HeaderVerifierTestState::new(); + let bls_key_1 = ManagedBuffer::from("bls_key_1"); + let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); + + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); + + let sovereign_config = SovereignConfig::new(0, 0, BigUint::default(), None); + + state.deploy_chain_config(&sovereign_config, HEADER_VERIFIER_ADDRESS); + + let new_validator_set = state.get_bls_keys(vec![ManagedBuffer::from("some_other_bls_key")]); + state.change_validator_set( + new_validator_set, + Some("The current validator set lenght doesn't meet the Sovereign's requirements"), + ); +} + +#[test] +fn change_validator_set() { + let mut state = HeaderVerifierTestState::new(); + let bls_key_1 = ManagedBuffer::from("bls_key_1"); + let managed_bls_keys = state.get_bls_keys(vec![bls_key_1]); + + state.deploy_header_verifier_contract(CHAIN_CONFIG_ADDRESS, managed_bls_keys); + + let sovereign_config = SovereignConfig::new(1, 2, BigUint::default(), None); + + state.deploy_chain_config(&sovereign_config, HEADER_VERIFIER_ADDRESS); + + let new_validator_set = state.get_bls_keys(vec![ + ManagedBuffer::from("new_key_1"), + ManagedBuffer::from("new_key_2"), + ]); + state.change_validator_set(new_validator_set, None); + + state + .world + .query() + .to(HEADER_VERIFIER_ADDRESS) + .whitebox(header_verifier::contract_obj, |sc| { + assert!(!sc.bls_pub_keys().is_empty()); + + let bls_key_1 = ManagedBuffer::from("new_key_1"); + let bls_key_2 = ManagedBuffer::from("new_key_2"); + + assert!(sc.bls_pub_keys().contains(&bls_key_1)); + assert!(sc.bls_pub_keys().contains(&bls_key_2)); + }) +} diff --git a/header-verifier/wasm-header-verifier-full/Cargo.lock b/header-verifier/wasm-header-verifier-full/Cargo.lock index 63d72c93..d7412c10 100644 --- a/header-verifier/wasm-header-verifier-full/Cargo.lock +++ b/header-verifier/wasm-header-verifier-full/Cargo.lock @@ -20,6 +20,17 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "chain-config" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", + "operation", + "proxies", + "setup-phase", +] + [[package]] name = "endian-type" version = "0.1.2" @@ -30,6 +41,7 @@ checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" name = "header-verifier" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "operation", "proxies", @@ -117,6 +129,15 @@ dependencies = [ "syn", ] +[[package]] +name = "multiversx-sc-modules" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa55a68bd4eb79f38bb8d526fb0fb6e9146b0a7195a92efd030fefa4341dad7" +dependencies = [ + "multiversx-sc", +] + [[package]] name = "multiversx-sc-wasm-adapter" version = "0.55.0" diff --git a/header-verifier/wasm-header-verifier-full/src/lib.rs b/header-verifier/wasm-header-verifier-full/src/lib.rs index 31cdc8ff..12d5f2f9 100644 --- a/header-verifier/wasm-header-verifier-full/src/lib.rs +++ b/header-verifier/wasm-header-verifier-full/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 5 +// Endpoints: 7 // Async Callback (empty): 1 -// Total number of exported functions: 8 +// Total number of exported functions: 10 #![no_std] @@ -24,6 +24,8 @@ multiversx_sc_wasm_adapter::endpoints! { setEsdtSafeAddress => set_esdt_safe_address removeExecutedHash => remove_executed_hash lockOperationHash => lock_operation_hash + changeValidatorSet => change_validator_set + updateConfig => update_config completeSetupPhase => complete_setup_phase ) } diff --git a/header-verifier/wasm-multisig-view/Cargo.lock b/header-verifier/wasm-multisig-view/Cargo.lock index 24f6ba1c..8c43ad54 100644 --- a/header-verifier/wasm-multisig-view/Cargo.lock +++ b/header-verifier/wasm-multisig-view/Cargo.lock @@ -20,6 +20,17 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "chain-config" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", + "operation", + "proxies", + "setup-phase", +] + [[package]] name = "endian-type" version = "0.1.2" @@ -30,6 +41,7 @@ checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" name = "header-verifier" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "operation", "proxies", @@ -117,6 +129,15 @@ dependencies = [ "syn", ] +[[package]] +name = "multiversx-sc-modules" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa55a68bd4eb79f38bb8d526fb0fb6e9146b0a7195a92efd030fefa4341dad7" +dependencies = [ + "multiversx-sc", +] + [[package]] name = "multiversx-sc-wasm-adapter" version = "0.55.0" diff --git a/header-verifier/wasm/Cargo.lock b/header-verifier/wasm/Cargo.lock index 077f8e60..6a201e84 100644 --- a/header-verifier/wasm/Cargo.lock +++ b/header-verifier/wasm/Cargo.lock @@ -20,6 +20,17 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "chain-config" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", + "operation", + "proxies", + "setup-phase", +] + [[package]] name = "endian-type" version = "0.1.2" @@ -30,6 +41,7 @@ checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" name = "header-verifier" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "operation", "proxies", @@ -117,6 +129,15 @@ dependencies = [ "syn", ] +[[package]] +name = "multiversx-sc-modules" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa55a68bd4eb79f38bb8d526fb0fb6e9146b0a7195a92efd030fefa4341dad7" +dependencies = [ + "multiversx-sc", +] + [[package]] name = "multiversx-sc-wasm-adapter" version = "0.55.0" diff --git a/header-verifier/wasm/src/lib.rs b/header-verifier/wasm/src/lib.rs index 31cdc8ff..12d5f2f9 100644 --- a/header-verifier/wasm/src/lib.rs +++ b/header-verifier/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 5 +// Endpoints: 7 // Async Callback (empty): 1 -// Total number of exported functions: 8 +// Total number of exported functions: 10 #![no_std] @@ -24,6 +24,8 @@ multiversx_sc_wasm_adapter::endpoints! { setEsdtSafeAddress => set_esdt_safe_address removeExecutedHash => remove_executed_hash lockOperationHash => lock_operation_hash + changeValidatorSet => change_validator_set + updateConfig => update_config completeSetupPhase => complete_setup_phase ) } diff --git a/sovereign-forge/interactor/src/interact.rs b/sovereign-forge/interactor/src/interact.rs index 305d3be5..cef591b0 100644 --- a/sovereign-forge/interactor/src/interact.rs +++ b/sovereign-forge/interactor/src/interact.rs @@ -4,6 +4,7 @@ mod config; use config::Config; use multiversx_sc_snippets::{imports::*, sdk::bech32}; +use operation::SovereignConfig; use proxies::{ chain_config_proxy::ChainConfigContractProxy, chain_factory_proxy::ChainFactoryContractProxy, @@ -17,7 +18,6 @@ use std::{ io::{Read, Write}, path::Path, }; -use operation::SovereignConfig; const STATE_FILE: &str = "state.toml"; const CHAIN_CONFIG_CODE_PATH: &str = "../../chain-config/output/chain-config.mxsc.json"; @@ -246,13 +246,15 @@ impl ContractInteract { } pub async fn deploy_header_verifier_template(&mut self) { + let chain_config_address = Bech32Address::from_bech32_string("chain_config".to_string()); + let new_address = self .interactor .tx() .from(&self.wallet_address) .gas(50_000_000u64) .typed(HeaderverifierProxy) - .init(MultiValueEncoded::new()) + .init(chain_config_address, MultiValueEncoded::new()) .returns(ReturnsNewAddress) .code(MxscPath::new(HEADER_VERIFIER_CODE_PATH)) .run() diff --git a/sovereign-forge/src/common/sc_deploy.rs b/sovereign-forge/src/common/sc_deploy.rs index b3c0c911..1ce03fa3 100644 --- a/sovereign-forge/src/common/sc_deploy.rs +++ b/sovereign-forge/src/common/sc_deploy.rs @@ -16,11 +16,15 @@ pub trait ScDeployModule: super::utils::UtilsModule + super::storage::StorageMod } #[inline] - fn deploy_header_verifier(&self, bls_keys: MultiValueEncoded) -> ManagedAddress { + fn deploy_header_verifier( + &self, + chain_config_address: ManagedAddress, + bls_keys: MultiValueEncoded, + ) -> ManagedAddress { self.tx() .to(self.get_chain_factory_address()) .typed(ChainFactoryContractProxy) - .deploy_header_verifier(bls_keys) + .deploy_header_verifier(chain_config_address, bls_keys) .returns(ReturnsResult) .sync_call() } diff --git a/sovereign-forge/src/phases.rs b/sovereign-forge/src/phases.rs index 0226fe8a..4b34294d 100644 --- a/sovereign-forge/src/phases.rs +++ b/sovereign-forge/src/phases.rs @@ -88,7 +88,8 @@ pub trait PhasesModule: "The Header-Verifier contract is already deployed" ); - let header_verifier_address = self.deploy_header_verifier(bls_keys); + let chain_config_address = self.get_contract_address(&caller, ScArray::ChainConfig); + let header_verifier_address = self.deploy_header_verifier(chain_config_address, bls_keys); let header_verifier_contract_info = ContractInfo::new(ScArray::HeaderVerifier, header_verifier_address); diff --git a/sovereign-forge/tests/sovereign_forge_unit_tests.rs b/sovereign-forge/tests/sovereign_forge_unit_tests.rs index 0c0cf866..e4081812 100644 --- a/sovereign-forge/tests/sovereign_forge_unit_tests.rs +++ b/sovereign-forge/tests/sovereign_forge_unit_tests.rs @@ -41,6 +41,8 @@ const FEE_MARKET_CODE_PATH: MxscPath = MxscPath::new("../fee-market/output/fee-m const TOKEN_HANDLER_ADDRESS: TestSCAddress = TestSCAddress::new("token-handler"); +const CHAIN_CONFIG_ADDRESS: TestSCAddress = TestSCAddress::new("chain-config"); + const BALANCE: u128 = 100_000_000_000_000_000; const DEPLOY_COST: u64 = 100_000; @@ -135,7 +137,7 @@ impl SovereignForgeTestState { .tx() .from(OWNER_ADDRESS) .typed(HeaderverifierProxy) - .init(bls_pub_keys) + .init(CHAIN_CONFIG_ADDRESS, bls_pub_keys) .code(HEADER_VERIFIER_CODE_PATH) .new_address(HEADER_VERIFIER_ADDRESS) .run(); diff --git a/sovereign-forge/wasm-sovereign-forge-full/Cargo.lock b/sovereign-forge/wasm-sovereign-forge-full/Cargo.lock index 3293a10e..5ff64ddd 100644 --- a/sovereign-forge/wasm-sovereign-forge-full/Cargo.lock +++ b/sovereign-forge/wasm-sovereign-forge-full/Cargo.lock @@ -81,6 +81,7 @@ dependencies = [ name = "header-verifier" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "operation", "proxies", diff --git a/sovereign-forge/wasm-soveriegn-forge-view/Cargo.lock b/sovereign-forge/wasm-soveriegn-forge-view/Cargo.lock index d9fe25e4..6d7fb5a1 100644 --- a/sovereign-forge/wasm-soveriegn-forge-view/Cargo.lock +++ b/sovereign-forge/wasm-soveriegn-forge-view/Cargo.lock @@ -81,6 +81,7 @@ dependencies = [ name = "header-verifier" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "operation", "proxies", diff --git a/sovereign-forge/wasm/Cargo.lock b/sovereign-forge/wasm/Cargo.lock index 76910528..75c8895f 100644 --- a/sovereign-forge/wasm/Cargo.lock +++ b/sovereign-forge/wasm/Cargo.lock @@ -81,6 +81,7 @@ dependencies = [ name = "header-verifier" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "operation", "proxies",