Skip to content

Commit 7d39768

Browse files
author
Seulgi Kim
committed
Add SetWorldOwners transaction
1 parent 268c579 commit 7d39768

File tree

7 files changed

+447
-3
lines changed

7 files changed

+447
-3
lines changed

core/src/client/client.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,9 @@ impl AssetClient for Client {
285285
Some(Transaction::CreateWorld {
286286
..
287287
}) => false,
288+
Some(Transaction::SetWorldOwners {
289+
..
290+
}) => false,
288291
Some(Transaction::AssetMint {
289292
shard_id: asset_mint_shard_id,
290293
..

core/src/parcel.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ impl UnverifiedParcel {
156156
Transaction::CreateWorld {
157157
..
158158
} => {}
159+
Transaction::SetWorldOwners {
160+
..
161+
} => {}
159162
Transaction::AssetMint {
160163
metadata,
161164
..

state/src/impls/shard_level.rs

Lines changed: 162 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ impl<B: Backend + ShardBackend> ShardLevelState<B> {
107107
&mut self,
108108
shard_id: ShardId,
109109
transaction: &Transaction,
110-
_sender: &Address,
111-
_shard_owner: &Address,
110+
sender: &Address,
111+
shard_owner: &Address,
112112
) -> StateResult<()> {
113113
debug_assert_eq!(Ok(()), transaction.verify());
114114
match transaction {
@@ -117,6 +117,13 @@ impl<B: Backend + ShardBackend> ShardLevelState<B> {
117117
owners,
118118
..
119119
} => Ok(self.create_world(shard_id, nonce, owners)?),
120+
Transaction::SetWorldOwners {
121+
shard_id,
122+
world_id,
123+
nonce,
124+
owners,
125+
..
126+
} => Ok(self.set_world_owners(*shard_id, *world_id, *nonce, &owners, sender, shard_owner)?),
120127
Transaction::AssetMint {
121128
metadata,
122129
registrar,
@@ -159,6 +166,35 @@ impl<B: Backend + ShardBackend> ShardLevelState<B> {
159166
Ok(())
160167
}
161168

169+
fn set_world_owners(
170+
&mut self,
171+
shard_id: ShardId,
172+
world_id: WorldId,
173+
nonce: u64,
174+
owners: &[Address],
175+
sender: &Address,
176+
shard_owner: &Address,
177+
) -> StateResult<()> {
178+
let world: World = self.world(world_id)?.ok_or_else(|| TransactionError::InvalidWorldId(world_id))?;
179+
180+
if shard_owner != sender && !world.world_owners().contains(sender) {
181+
return Err(TransactionError::InsufficientPermission.into())
182+
}
183+
184+
let current_nonce = world.nonce();
185+
if current_nonce != &nonce {
186+
return Err(TransactionError::InvalidWorldNonce(Mismatch {
187+
expected: *current_nonce,
188+
found: nonce,
189+
}).into())
190+
}
191+
192+
let mut world = self.require_world(&WorldAddress::new(shard_id, world_id), || unreachable!())?;
193+
world.inc_nonce();
194+
world.set_owners(owners.to_vec());
195+
Ok(())
196+
}
197+
162198
fn mint_asset(
163199
&mut self,
164200
transaction_hash: H256,
@@ -906,4 +942,128 @@ mod tests {
906942
let asset2 = state.asset(&asset2_address);
907943
assert_eq!(Ok(Some(Asset::new(asset_type, random_lock_script_hash, vec![], 15))), asset2);
908944
}
945+
946+
#[test]
947+
fn shard_owner_can_set_world_owners() {
948+
let network_id = 0xDEADBEEF;
949+
let shard_id = 0xCAFE;
950+
let mut state = get_temp_shard_state(shard_id);
951+
952+
let owners = vec![Address::random(), Address::random()];
953+
assert_eq!(Ok(()), state.create_world(shard_id, &0, &owners));
954+
assert_eq!(Ok(()), state.commit());
955+
956+
let metadata = state.metadata();
957+
assert_eq!(Ok(Some(ShardMetadata::new_with_nonce(1, 1))), metadata);
958+
959+
let world_id = 0;
960+
let world = state.world(world_id);
961+
assert_eq!(Ok(Some(World::new(owners))), world);
962+
963+
let nonce = 0;
964+
965+
let new_owners = vec![Address::random(), Address::random(), Address::random()];
966+
let transaction = Transaction::SetWorldOwners {
967+
network_id,
968+
shard_id,
969+
world_id,
970+
nonce,
971+
owners: new_owners.clone(),
972+
};
973+
974+
let shard_owner = {
975+
loop {
976+
let owner = address();
977+
if !new_owners.contains(&owner) {
978+
break owner
979+
}
980+
}
981+
};
982+
assert_eq!(Ok(TransactionInvoice::Success), state.apply(shard_id, &transaction, &shard_owner, &shard_owner));
983+
984+
let world = state.world(world_id);
985+
assert_eq!(Ok(Some(World::new_with_nonce(new_owners, 1))), world);
986+
}
987+
988+
#[test]
989+
fn world_owner_can_set_world_owners() {
990+
let network_id = 0xDEADBEEF;
991+
let shard_id = 0xCAFE;
992+
let mut state = get_temp_shard_state(shard_id);
993+
994+
let sender = Address::random();
995+
let old_owners = vec![sender, Address::random()];
996+
assert_eq!(Ok(()), state.create_world(shard_id, &0, &old_owners));
997+
assert_eq!(Ok(()), state.commit());
998+
999+
let metadata = state.metadata();
1000+
assert_eq!(Ok(Some(ShardMetadata::new_with_nonce(1, 1))), metadata);
1001+
1002+
let world_id = 0;
1003+
let world = state.world(world_id);
1004+
assert_eq!(Ok(Some(World::new(old_owners.clone()))), world);
1005+
1006+
let nonce = 0;
1007+
1008+
let owners = vec![Address::random(), Address::random(), Address::random()];
1009+
let transaction = Transaction::SetWorldOwners {
1010+
network_id,
1011+
shard_id,
1012+
world_id,
1013+
nonce,
1014+
owners: owners.clone(),
1015+
};
1016+
1017+
let shard_owner = Address::random();
1018+
assert_eq!(Ok(TransactionInvoice::Success), state.apply(shard_id, &transaction, &sender, &shard_owner));
1019+
1020+
let world = state.world(world_id);
1021+
assert_eq!(Ok(Some(World::new_with_nonce(owners, 1))), world);
1022+
}
1023+
1024+
1025+
#[test]
1026+
fn insufficient_permission_must_fail_to_set_world_owners() {
1027+
let network_id = 0xDEADBEEF;
1028+
let shard_id = 0xCAFE;
1029+
let mut state = get_temp_shard_state(shard_id);
1030+
1031+
let owners = vec![Address::random(), Address::random()];
1032+
assert_eq!(Ok(()), state.create_world(shard_id, &0, &owners));
1033+
assert_eq!(Ok(()), state.commit());
1034+
1035+
let metadata = state.metadata();
1036+
assert_eq!(Ok(Some(ShardMetadata::new_with_nonce(1, 1))), metadata);
1037+
1038+
let world_id = 0;
1039+
let world = state.world(world_id);
1040+
assert_eq!(Ok(Some(World::new(owners.clone()))), world);
1041+
1042+
let nonce = 0;
1043+
1044+
let new_owners = vec![Address::random(), Address::random(), Address::random()];
1045+
let transaction = Transaction::SetWorldOwners {
1046+
network_id,
1047+
shard_id,
1048+
world_id,
1049+
nonce,
1050+
owners: new_owners.clone(),
1051+
};
1052+
1053+
let sender = {
1054+
loop {
1055+
let owner = address();
1056+
if !new_owners.contains(&owner) {
1057+
break owner
1058+
}
1059+
}
1060+
};
1061+
let shard_owner = address();
1062+
assert_eq!(
1063+
Ok(TransactionInvoice::Fail(TransactionError::InsufficientPermission)),
1064+
state.apply(shard_id, &transaction, &sender, &shard_owner)
1065+
);
1066+
let world = state.world(world_id);
1067+
assert_eq!(Ok(Some(World::new_with_nonce(owners, 0))), world);
1068+
}
9091069
}

state/src/impls/top_level.rs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2085,4 +2085,144 @@ mod tests_parcel {
20852085
let res = state.apply(&parcel, &sender, &sender_public);
20862086
assert_eq!(Err(StateError::Parcel(ParcelError::InvalidShardId(100))), res);
20872087
}
2088+
2089+
#[test]
2090+
fn create_world_and_set_owners_in_the_same_parcel() {
2091+
let (sender, sender_public) = address();
2092+
2093+
let mut state = get_temp_state();
2094+
assert_eq!(Ok(()), state.create_shard_level_state(&sender));
2095+
assert_eq!(Ok(()), state.commit());
2096+
2097+
let shard_id = 0x00;
2098+
let network_id = 0xBeef;
2099+
let world_id = 0;
2100+
2101+
let owners = vec![Address::random(), Address::random()];
2102+
2103+
let t0 = Transaction::CreateWorld {
2104+
network_id,
2105+
shard_id,
2106+
nonce: 0,
2107+
owners: vec![Address::random()],
2108+
};
2109+
let t1 = Transaction::SetWorldOwners {
2110+
network_id,
2111+
shard_id,
2112+
world_id,
2113+
nonce: 0,
2114+
owners: owners.clone(),
2115+
};
2116+
2117+
let transactions = vec![t0, t1];
2118+
let parcel = Parcel {
2119+
fee: 20.into(),
2120+
nonce: 0.into(),
2121+
network_id,
2122+
action: Action::ChangeShardState {
2123+
transactions,
2124+
changes: vec![ChangeShard {
2125+
shard_id,
2126+
pre_root: H256::from("0xa8ed01b49cd63c6a547ac3ce357539aa634fb44331a351e3e98b9f1c3a8e3edf"),
2127+
post_root: H256::zero(),
2128+
}],
2129+
signatures: vec![],
2130+
},
2131+
};
2132+
2133+
assert_eq!(Ok(()), state.add_balance(&sender, &120.into()));
2134+
assert_eq!(Ok(120.into()), state.balance(&sender));
2135+
2136+
assert_eq!(
2137+
Ok(ParcelInvoice::Multiple(vec![TransactionInvoice::Success, TransactionInvoice::Success])),
2138+
state.apply(&parcel, &sender, &sender_public)
2139+
);
2140+
2141+
assert_eq!(Ok(100.into()), state.balance(&sender));
2142+
assert_eq!(Ok(1.into()), state.nonce(&sender));
2143+
2144+
assert_eq!(Ok(Some(World::new_with_nonce(owners, 1))), state.world(shard_id, world_id));
2145+
}
2146+
2147+
#[test]
2148+
fn create_world_and_set_owners_in_different_parcel() {
2149+
let (sender, sender_public) = address();
2150+
2151+
let mut state = get_temp_state();
2152+
assert_eq!(Ok(()), state.create_shard_level_state(&sender));
2153+
assert_eq!(Ok(()), state.commit());
2154+
2155+
let shard_id = 0x00;
2156+
let network_id = 0xBeef;
2157+
let world_id = 0;
2158+
2159+
assert_eq!(Ok(()), state.add_balance(&sender, &120.into()));
2160+
assert_eq!(Ok(120.into()), state.balance(&sender));
2161+
2162+
let old_owners = vec![Address::random(), Address::random(), Address::random()];
2163+
let new_owners = vec![Address::random(), Address::random()];
2164+
2165+
let t0 = Transaction::CreateWorld {
2166+
network_id,
2167+
shard_id,
2168+
nonce: 0,
2169+
owners: old_owners.clone(),
2170+
};
2171+
2172+
let parcel0 = Parcel {
2173+
fee: 20.into(),
2174+
nonce: 0.into(),
2175+
network_id,
2176+
action: Action::ChangeShardState {
2177+
transactions: vec![t0],
2178+
changes: vec![ChangeShard {
2179+
shard_id,
2180+
pre_root: H256::from("0xa8ed01b49cd63c6a547ac3ce357539aa634fb44331a351e3e98b9f1c3a8e3edf"),
2181+
post_root: H256::zero(),
2182+
}],
2183+
signatures: vec![],
2184+
},
2185+
};
2186+
2187+
assert_eq!(
2188+
Ok(ParcelInvoice::Multiple(vec![TransactionInvoice::Success])),
2189+
state.apply(&parcel0, &sender, &sender_public)
2190+
);
2191+
2192+
assert_eq!(Ok(100.into()), state.balance(&sender));
2193+
assert_eq!(Ok(1.into()), state.nonce(&sender));
2194+
assert_eq!(Ok(Some(World::new_with_nonce(old_owners, 0))), state.world(shard_id, world_id));
2195+
2196+
let t1 = Transaction::SetWorldOwners {
2197+
network_id,
2198+
shard_id,
2199+
world_id,
2200+
nonce: 0,
2201+
owners: new_owners.clone(),
2202+
};
2203+
2204+
let parcel1 = Parcel {
2205+
fee: 30.into(),
2206+
nonce: 1.into(),
2207+
network_id,
2208+
action: Action::ChangeShardState {
2209+
transactions: vec![t1],
2210+
changes: vec![ChangeShard {
2211+
shard_id,
2212+
pre_root: H256::zero(),
2213+
post_root: H256::zero(),
2214+
}],
2215+
signatures: vec![],
2216+
},
2217+
};
2218+
2219+
assert_eq!(
2220+
Ok(ParcelInvoice::Multiple(vec![TransactionInvoice::Success])),
2221+
state.apply(&parcel1, &sender, &sender_public)
2222+
);
2223+
2224+
assert_eq!(Ok(70.into()), state.balance(&sender));
2225+
assert_eq!(Ok(2.into()), state.nonce(&sender));
2226+
assert_eq!(Ok(Some(World::new_with_nonce(new_owners, 1))), state.world(shard_id, world_id));
2227+
}
20882228
}

state/src/item/world.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ impl World {
4949
pub fn nonce(&self) -> &u64 {
5050
&self.nonce
5151
}
52+
53+
pub fn inc_nonce(&mut self) {
54+
debug_assert_ne!(::std::u64::MAX, self.nonce);
55+
self.nonce += 1;
56+
}
57+
58+
pub fn set_owners(&mut self, owners: Vec<Address>) {
59+
debug_assert_ne!(Vec::<Address>::new(), owners);
60+
self.world_owners = owners;
61+
}
5262
}
5363

5464
impl CacheableItem for World {

0 commit comments

Comments
 (0)