Skip to content

Commit

Permalink
feat: collective approval or single council member can also cancel co…
Browse files Browse the repository at this point in the history
…ntract
  • Loading branch information
renauter committed Nov 6, 2023
1 parent 38ea787 commit 8fc1e25
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 16 deletions.
2 changes: 1 addition & 1 deletion clients/tfchain-client-go/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ var smartContractModuleErrors = []string{
"FailedToFreeIPs",
"ContractNotExists",
"TwinNotAuthorizedToUpdateContract",
"TwinNotAuthorizedToCancelContract",
"NotAuthorizedToCancelContract",
"NodeNotAuthorizedToDeployContract",
"NodeNotAuthorizedToComputeReport",
"PricingPolicyNotExists",
Expand Down
2 changes: 2 additions & 0 deletions substrate-node/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions substrate-node/pallets/pallet-smart-contract/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ substrate-fixed = { git = 'https://github.com/encointer/substrate-fixed.git', re
pallet-balances.workspace = true
frame-support.workspace = true
frame-system.workspace = true
pallet-membership.workspace = true
pallet-collective.workspace = true
sp-runtime.workspace = true
sp-std.workspace = true
pallet-timestamp.workspace = true
Expand Down Expand Up @@ -66,6 +68,8 @@ std = [
'scale-info/std',
'frame-benchmarking/std',
'sp-io/std',
"pallet-membership/std",
"pallet-collective/std",
'frame-try-runtime/std',
'sp-core/std',
'pallet-authorship/std',
Expand Down
44 changes: 34 additions & 10 deletions substrate-node/pallets/pallet-smart-contract/src/grid_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ use frame_support::{
dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Pays},
ensure,
pallet_prelude::TypeInfo,
traits::EnsureOrigin,
BoundedVec, RuntimeDebugNoBound,
};
use frame_system::{ensure_signed, pallet_prelude::OriginFor};
use pallet_tfgrid::pallet::{InterfaceOf, LocationOf, SerialNumberOf, TfgridNode};
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use sp_std::{marker::PhantomData, vec, vec::Vec};
Expand Down Expand Up @@ -277,19 +279,34 @@ impl<T: Config> Pallet<T> {
Ok(().into())
}

pub fn _cancel_contract(
account_id: T::AccountId,
contract_id: u64,
cause: types::Cause,
) -> DispatchResultWithPostInfo {
pub fn _cancel_contract(origin: OriginFor<T>, contract_id: u64) -> DispatchResultWithPostInfo {
let mut contract = Contracts::<T>::get(contract_id).ok_or(Error::<T>::ContractNotExists)?;

// Allow collective approval (council or farmers) to cancel contract
if <T as Config>::RestrictedOrigin::ensure_origin(origin.clone()).is_ok() {
return Self::_do_cancel_contract(&mut contract, types::Cause::CanceledByCollective);
}

// Allow single council member cancel contract
let account_id = ensure_signed(origin)?;
if Self::is_council_member(account_id.clone()) {
return Self::_do_cancel_contract(&mut contract, types::Cause::CanceledByCouncilMember);
}

// Allow node the contract is on to cancel contract
let twin =
pallet_tfgrid::Twins::<T>::get(contract.twin_id).ok_or(Error::<T>::TwinNotExists)?;
ensure!(
twin.account_id == account_id,
Error::<T>::TwinNotAuthorizedToCancelContract
);
if twin.account_id == account_id {
return Self::_do_cancel_contract(&mut contract, types::Cause::CanceledByNode);
}

Err(Error::<T>::NotAuthorizedToCancelContract.into())
}

pub fn _do_cancel_contract(
contract: &mut types::Contract<T>,
cause: types::Cause,
) -> DispatchResultWithPostInfo {
// If it's a rent contract and it still has active workloads, don't allow cancellation.
if matches!(
&contract.contract_type,
Expand All @@ -303,7 +320,7 @@ impl<T: Config> Pallet<T> {
);
}

Self::update_contract_state(&mut contract, &types::ContractState::Deleted(cause))?;
Self::update_contract_state(contract, &types::ContractState::Deleted(cause))?;
Self::bill_contract(contract.contract_id)?;

Ok(().into())
Expand Down Expand Up @@ -651,6 +668,13 @@ impl<T: Config> Pallet<T> {

Ok(().into())
}

fn is_council_member(who: T::AccountId) -> bool {
let council_members =
pallet_membership::Pallet::<T, pallet_membership::Instance1>::members();

council_members.contains(&who)
}
}

impl<T: Config> PublicIpModifier for Pallet<T> {
Expand Down
6 changes: 3 additions & 3 deletions substrate-node/pallets/pallet-smart-contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ pub mod pallet {
+ pallet_tft_price::Config
+ pallet_authorship::Config
+ pallet_session::Config
+ pallet_membership::Config<pallet_membership::Instance1>
{
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type Currency: LockableCurrency<Self::AccountId>;
Expand Down Expand Up @@ -343,7 +344,7 @@ pub mod pallet {
FailedToFreeIPs,
ContractNotExists,
TwinNotAuthorizedToUpdateContract,
TwinNotAuthorizedToCancelContract,
NotAuthorizedToCancelContract,
NodeNotAuthorizedToDeployContract,
NodeNotAuthorizedToComputeReport,
PricingPolicyNotExists,
Expand Down Expand Up @@ -451,8 +452,7 @@ pub mod pallet {
origin: OriginFor<T>,
contract_id: u64,
) -> DispatchResultWithPostInfo {
let account_id = ensure_signed(origin)?;
Self::_cancel_contract(account_id, contract_id, types::Cause::CanceledByUser)
Self::_cancel_contract(origin, contract_id)
}

#[pallet::call_index(4)]
Expand Down
38 changes: 37 additions & 1 deletion substrate-node/pallets/pallet-smart-contract/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ construct_runtime!(
Authorship: pallet_authorship::{Pallet, Storage},
ValidatorSet: substrate_validator_set::{Pallet, Call, Storage, Event<T>, Config<T>},
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
Council: pallet_collective::<Instance1>::{Pallet, Call, Origin<T>, Event<T>, Config<T>},
Membership: pallet_membership::<Instance1>::{Pallet, Call, Storage, Event<T>},
}
);

Expand Down Expand Up @@ -365,7 +367,39 @@ impl pallet_session::Config for TestRuntime {
type WeightInfo = ();
}

type AccountPublic = <MultiSignature as Verify>::Signer;
pub type BlockNumber = u32;
parameter_types! {
pub const CouncilMotionDuration: BlockNumber = 4;
pub const CouncilMaxProposals: u32 = 100;
pub const CouncilMaxMembers: u32 = 100;
}

pub type CouncilCollective = pallet_collective::Instance1;
impl pallet_collective::Config<CouncilCollective> for TestRuntime {
type RuntimeOrigin = RuntimeOrigin;
type Proposal = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type MotionDuration = CouncilMotionDuration;
type MaxProposals = CouncilMaxProposals;
type MaxMembers = CouncilMaxMembers;
type DefaultVote = pallet_collective::PrimeDefaultVote;
type SetMembersOrigin = EnsureRoot<Self::AccountId>;
type WeightInfo = ();
type MaxProposalWeight = ();
}

impl pallet_membership::Config<pallet_membership::Instance1> for TestRuntime {
type RuntimeEvent = RuntimeEvent;
type AddOrigin = EnsureRoot<Self::AccountId>;
type RemoveOrigin = EnsureRoot<Self::AccountId>;
type SwapOrigin = EnsureRoot<Self::AccountId>;
type ResetOrigin = EnsureRoot<Self::AccountId>;
type PrimeOrigin = EnsureRoot<Self::AccountId>;
type MembershipInitialized = Council;
type MembershipChanged = ();
type MaxMembers = CouncilMaxMembers;
type WeightInfo = pallet_membership::weights::SubstrateWeight<TestRuntime>;
}

pub(crate) fn get_name_contract_name(contract_name_input: &[u8]) -> TestNameContractName {
NameContractName::try_from(contract_name_input.to_vec()).expect("Invalid farm input.")
Expand Down Expand Up @@ -445,6 +479,8 @@ where
}
}

type AccountPublic = <MultiSignature as Verify>::Signer;

/// Helper function to generate an account ID from seed
fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
where
Expand Down
2 changes: 1 addition & 1 deletion substrate-node/pallets/pallet-smart-contract/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ fn test_cancel_node_contract_wrong_twins_fails() {

assert_noop!(
SmartContractModule::cancel_contract(RuntimeOrigin::signed(bob()), contract_id),
Error::<TestRuntime>::TwinNotAuthorizedToCancelContract
Error::<TestRuntime>::NotAuthorizedToCancelContract
);
});
}
Expand Down
3 changes: 3 additions & 0 deletions substrate-node/pallets/pallet-smart-contract/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,10 @@ pub enum ContractState {

#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
pub enum Cause {
CanceledByNode,
CanceledByUser,
CanceledByCouncilMember,
CanceledByCollective,
OutOfFunds,
}

Expand Down

0 comments on commit 8fc1e25

Please sign in to comment.