@@ -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}
0 commit comments