Skip to content

Commit ab52c46

Browse files
author
Seulgi Kim
committed
Add ChangeShardOwners parcel
1 parent aaa49a1 commit ab52c46

File tree

4 files changed

+228
-0
lines changed

4 files changed

+228
-0
lines changed

state/src/impls/top_level.rs

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,13 @@ impl TopLevelState {
452452
self.create_shard(&shard_creation_cost, fee_payer)?;
453453
Ok(ParcelInvoice::SingleSuccess)
454454
}
455+
Action::ChangeShardOwners {
456+
shard_id,
457+
owners,
458+
} => {
459+
self.change_shard_owners(*shard_id, owners, fee_payer)?;
460+
Ok(ParcelInvoice::SingleSuccess)
461+
}
455462
Action::Custom(bytes) => {
456463
let handlers = self.db.custom_handlers().to_vec();
457464
for h in handlers {
@@ -790,6 +797,18 @@ impl TopState<StateDB> for TopLevelState {
790797
Ok(())
791798
}
792799

800+
fn change_shard_owners(&mut self, shard_id: ShardId, owners: &[Address], sender: &Address) -> StateResult<()> {
801+
let old_owners = self.shard_owners(shard_id)?.ok_or_else(|| ParcelError::InvalidShardId(shard_id))?;
802+
if !old_owners.contains(sender) {
803+
return Err(ParcelError::InsufficientPermission.into())
804+
}
805+
if !owners.contains(sender) {
806+
return Err(ParcelError::NewOwnersMustContainSender.into())
807+
}
808+
809+
self.set_shard_owners(shard_id, owners.to_vec())
810+
}
811+
793812
fn set_shard_root(&mut self, shard_id: ShardId, old_root: &H256, new_root: &H256) -> StateResult<()> {
794813
let mut shard = self.require_shard(shard_id)?;
795814
assert_eq!(old_root, shard.root());
@@ -2224,4 +2243,166 @@ mod tests_parcel {
22242243
assert_eq!(Ok(2.into()), state.nonce(&sender));
22252244
assert_eq!(Ok(Some(World::new_with_nonce(new_owners, 1))), state.world(shard_id, world_id));
22262245
}
2246+
2247+
#[test]
2248+
fn change_shard_owners() {
2249+
let (sender, sender_public) = address();
2250+
2251+
let mut state = get_temp_state();
2252+
assert_eq!(Ok(()), state.create_shard_level_state(&sender));
2253+
assert_eq!(Ok(()), state.add_balance(&sender, &U256::from(69u64)));
2254+
assert_eq!(Ok(()), state.commit());
2255+
2256+
let network_id = 0xCA;
2257+
let shard_id = 0;
2258+
let owners = vec![Address::random(), Address::random(), sender];
2259+
2260+
let parcel = Parcel {
2261+
fee: 5.into(),
2262+
action: Action::ChangeShardOwners {
2263+
shard_id,
2264+
owners: owners.clone(),
2265+
},
2266+
nonce: 0.into(),
2267+
network_id,
2268+
};
2269+
2270+
assert_eq!(Ok(Some(vec![sender])), state.shard_owners(shard_id));
2271+
2272+
assert_eq!(Ok(ParcelInvoice::SingleSuccess), state.apply(&parcel, &sender, &sender_public));
2273+
2274+
assert_eq!(Ok(64.into()), state.balance(&sender));
2275+
assert_eq!(Ok(1.into()), state.nonce(&sender));
2276+
assert_eq!(Ok(Some(owners)), state.shard_owners(shard_id));
2277+
}
2278+
2279+
#[test]
2280+
fn new_owners_must_contain_sender() {
2281+
let (sender, sender_public) = address();
2282+
2283+
let mut state = get_temp_state();
2284+
assert_eq!(Ok(()), state.create_shard_level_state(&sender));
2285+
assert_eq!(Ok(()), state.add_balance(&sender, &U256::from(69u64)));
2286+
assert_eq!(Ok(()), state.commit());
2287+
2288+
let network_id = 0xCA;
2289+
let shard_id = 0;
2290+
let owners = {
2291+
let a1 = loop {
2292+
let a = Address::random();
2293+
if a != sender {
2294+
break a
2295+
}
2296+
};
2297+
let a2 = loop {
2298+
let a = Address::random();
2299+
if a != sender {
2300+
break a
2301+
}
2302+
};
2303+
vec![a1, a2]
2304+
};
2305+
2306+
let parcel = Parcel {
2307+
fee: 5.into(),
2308+
action: Action::ChangeShardOwners {
2309+
shard_id,
2310+
owners,
2311+
},
2312+
nonce: 0.into(),
2313+
network_id,
2314+
};
2315+
2316+
assert_eq!(Ok(Some(vec![sender])), state.shard_owners(shard_id));
2317+
2318+
assert_eq!(Err(ParcelError::NewOwnersMustContainSender.into()), state.apply(&parcel, &sender, &sender_public));
2319+
2320+
assert_eq!(Ok(69.into()), state.balance(&sender));
2321+
assert_eq!(Ok(0.into()), state.nonce(&sender));
2322+
assert_eq!(Ok(Some(vec![sender])), state.shard_owners(shard_id));
2323+
}
2324+
2325+
#[test]
2326+
fn only_owner_can_change_owners() {
2327+
let (original_owner, _) = address();
2328+
2329+
let mut state = get_temp_state();
2330+
assert_eq!(Ok(()), state.create_shard_level_state(&original_owner));
2331+
let (sender, sender_public) = address();
2332+
assert_eq!(Ok(()), state.add_balance(&sender, &U256::from(69u64)));
2333+
assert_eq!(Ok(()), state.commit());
2334+
2335+
let network_id = 0xCA;
2336+
let shard_id = 0;
2337+
2338+
let owners = {
2339+
let a1 = loop {
2340+
let a = Address::random();
2341+
if a != original_owner {
2342+
break a
2343+
}
2344+
};
2345+
let a2 = loop {
2346+
let a = Address::random();
2347+
if a != original_owner {
2348+
break a
2349+
}
2350+
};
2351+
vec![a1, a2, sender]
2352+
};
2353+
2354+
let parcel = Parcel {
2355+
fee: 5.into(),
2356+
action: Action::ChangeShardOwners {
2357+
shard_id,
2358+
owners,
2359+
},
2360+
nonce: 0.into(),
2361+
network_id,
2362+
};
2363+
2364+
assert_eq!(Ok(Some(vec![original_owner])), state.shard_owners(shard_id));
2365+
2366+
assert_eq!(Err(ParcelError::InsufficientPermission.into()), state.apply(&parcel, &sender, &sender_public));
2367+
2368+
assert_eq!(Ok(69.into()), state.balance(&sender));
2369+
assert_eq!(Ok(0.into()), state.nonce(&sender));
2370+
assert_eq!(Ok(Some(vec![original_owner])), state.shard_owners(shard_id));
2371+
}
2372+
2373+
#[test]
2374+
fn change_shard_owners_fail_on_invalid_shard_id() {
2375+
let (sender, sender_public) = address();
2376+
2377+
let mut state = get_temp_state();
2378+
assert_eq!(Ok(()), state.create_shard_level_state(&sender));
2379+
assert_eq!(Ok(()), state.add_balance(&sender, &U256::from(69u64)));
2380+
assert_eq!(Ok(()), state.commit());
2381+
2382+
let network_id = 0xCA;
2383+
let real_shard_id = 0;
2384+
let shard_id = 0xF;
2385+
2386+
let owners = vec![Address::random(), Address::random(), sender];
2387+
2388+
let parcel = Parcel {
2389+
fee: 5.into(),
2390+
action: Action::ChangeShardOwners {
2391+
shard_id,
2392+
owners: owners.clone(),
2393+
},
2394+
nonce: 0.into(),
2395+
network_id,
2396+
};
2397+
2398+
assert_eq!(Ok(Some(vec![sender])), state.shard_owners(real_shard_id));
2399+
assert_eq!(Ok(None), state.shard_owners(shard_id));
2400+
2401+
assert_eq!(Err(ParcelError::InvalidShardId(shard_id).into()), state.apply(&parcel, &sender, &sender_public));
2402+
2403+
assert_eq!(Ok(69.into()), state.balance(&sender));
2404+
assert_eq!(Ok(0.into()), state.nonce(&sender));
2405+
assert_eq!(Ok(Some(vec![sender])), state.shard_owners(real_shard_id));
2406+
assert_eq!(Ok(None), state.shard_owners(shard_id));
2407+
}
22272408
}

state/src/traits.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ where
104104
fn set_regular_key(&mut self, master_public: &Public, key: &Public) -> StateResult<()>;
105105

106106
fn create_shard(&mut self, shard_creation_cost: &U256, fee_payer: &Address) -> StateResult<()>;
107+
fn change_shard_owners(&mut self, shard_id: ShardId, owners: &[Address], sender: &Address) -> StateResult<()>;
107108

108109
fn set_shard_root(&mut self, shard_id: ShardId, old_root: &H256, new_root: &H256) -> StateResult<()>;
109110
fn set_shard_owners(&mut self, shard_id: ShardId, new_owners: Vec<Address>) -> StateResult<()>;

types/src/parcel/action.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const CHANGE_SHARD_STATE: u8 = 1;
2626
const PAYMENT: u8 = 2;
2727
const SET_REGULAR_KEY: u8 = 3;
2828
const CREATE_SHARD: u8 = 4;
29+
const CHANGE_SHARD_OWNERS: u8 = 5;
2930
const CUSTOM: u8 = 0xFF;
3031

3132
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, RlpDecodable, RlpEncodable)]
@@ -54,6 +55,10 @@ pub enum Action {
5455
key: Public,
5556
},
5657
CreateShard,
58+
ChangeShardOwners {
59+
shard_id: ShardId,
60+
owners: Vec<Address>,
61+
},
5762
Custom(Bytes),
5863
}
5964

@@ -98,6 +103,15 @@ impl Encodable for Action {
98103
s.begin_list(1);
99104
s.append(&CREATE_SHARD);
100105
}
106+
Action::ChangeShardOwners {
107+
shard_id,
108+
owners,
109+
} => {
110+
s.begin_list(3);
111+
s.append(&CHANGE_SHARD_OWNERS);
112+
s.append(shard_id);
113+
s.append_list(owners);
114+
}
101115
Action::Custom(bytes) => {
102116
s.begin_list(2);
103117
s.append(&CUSTOM);
@@ -143,6 +157,15 @@ impl Decodable for Action {
143157
}
144158
Ok(Action::CreateShard)
145159
}
160+
CHANGE_SHARD_OWNERS => {
161+
if rlp.item_count()? != 3 {
162+
return Err(DecoderError::RlpIncorrectListLen)
163+
}
164+
Ok(Action::ChangeShardOwners {
165+
shard_id: rlp.val_at(1)?,
166+
owners: rlp.list_at(2)?,
167+
})
168+
}
146169
CUSTOM => {
147170
if rlp.item_count()? != 2 {
148171
return Err(DecoderError::RlpIncorrectListLen)
@@ -153,3 +176,16 @@ impl Decodable for Action {
153176
}
154177
}
155178
}
179+
180+
#[cfg(test)]
181+
mod tests {
182+
use super::*;
183+
184+
#[test]
185+
fn encode_and_decode_change_shard_owners() {
186+
rlp_encode_and_decode_test!(Action::ChangeShardOwners {
187+
shard_id: 1,
188+
owners: vec![Address::random(), Address::random()],
189+
});
190+
}
191+
}

types/src/parcel/error.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ pub enum Error {
7777
InvalidTransferDestination,
7878
/// Transaction error
7979
InvalidTransaction(TransactionError),
80+
InsufficientPermission,
81+
NewOwnersMustContainSender,
8082
}
8183

8284
const ERROR_ID_PARCEL_ALREADY_IMPORTED: u8 = 1u8;
@@ -99,6 +101,8 @@ const ERROR_ID_REGULAR_KEY_ALREADY_IN_USE: u8 = 17u8;
99101
const ERROR_ID_REGULAR_KEY_ALREADY_IN_USE_AS_MASTER: u8 = 18u8;
100102
const ERROR_ID_INVALID_TRANSFER_DESTINATION: u8 = 19u8;
101103
const ERROR_ID_INVALID_TRANSACTION: u8 = 20u8;
104+
const ERROR_ID_INSUFFICIENT_PERMISSION: u8 = 21u8;
105+
const ERROR_ID_NEW_OWNERS_MUST_CONTAIN_SENDER: u8 = 22u8;
102106

103107
impl Encodable for Error {
104108
fn rlp_append(&self, s: &mut RlpStream) {
@@ -135,6 +139,8 @@ impl Encodable for Error {
135139
}
136140
Error::InvalidTransferDestination => s.begin_list(1).append(&ERROR_ID_INVALID_TRANSFER_DESTINATION),
137141
Error::InvalidTransaction(err) => s.begin_list(2).append(&ERROR_ID_INVALID_TRANSACTION).append(err),
142+
Error::InsufficientPermission => s.begin_list(1).append(&ERROR_ID_INSUFFICIENT_PERMISSION),
143+
Error::NewOwnersMustContainSender => s.begin_list(1).append(&ERROR_ID_NEW_OWNERS_MUST_CONTAIN_SENDER),
138144
};
139145
}
140146
}
@@ -173,6 +179,8 @@ impl Decodable for Error {
173179
ERROR_ID_REGULAR_KEY_ALREADY_IN_USE_AS_MASTER => Error::RegularKeyAlreadyInUseAsMaster,
174180
ERROR_ID_INVALID_TRANSFER_DESTINATION => Error::InvalidTransferDestination,
175181
ERROR_ID_INVALID_TRANSACTION => Error::InvalidTransaction(rlp.val_at(1)?),
182+
ERROR_ID_INSUFFICIENT_PERMISSION => Error::InsufficientPermission,
183+
ERROR_ID_NEW_OWNERS_MUST_CONTAIN_SENDER => Error::NewOwnersMustContainSender,
176184
_ => return Err(DecoderError::Custom("Invalid parcel error")),
177185
})
178186
}
@@ -211,6 +219,8 @@ impl Display for Error {
211219
Error::RegularKeyAlreadyInUseAsMaster => "The regular key is already used as a master account".to_string(),
212220
Error::InvalidTransferDestination => "Transfer receiver is not valid account".to_string(),
213221
Error::InvalidTransaction(err) => format!("Parcel has an invalid transaction: {}", err).to_string(),
222+
Error::InsufficientPermission => "Sender doesn't have a permission".to_string(),
223+
Error::NewOwnersMustContainSender => "New owners must contain the sender".to_string(),
214224
};
215225

216226
f.write_fmt(format_args!("Parcel error ({})", msg))

0 commit comments

Comments
 (0)