@@ -109,6 +109,11 @@ impl<M: Message> ActionHandler for Stake<M> {
109109 address,
110110 quantity,
111111 } => revoke ( state, fee_payer, & address, quantity) ,
112+ Action :: Redelegate {
113+ prev_delegatee,
114+ next_delegatee,
115+ quantity,
116+ } => redelegate ( state, fee_payer, & prev_delegatee, & next_delegatee, quantity) ,
112117 Action :: SelfNominate {
113118 deposit,
114119 metadata,
@@ -226,6 +231,43 @@ fn revoke(state: &mut TopLevelState, fee_payer: &Address, delegatee: &Address, q
226231 Ok ( ( ) )
227232}
228233
234+ fn redelegate (
235+ state : & mut TopLevelState ,
236+ fee_payer : & Address ,
237+ prev_delegatee : & Address ,
238+ next_delegatee : & Address ,
239+ quantity : u64 ,
240+ ) -> StateResult < ( ) > {
241+ let candidates = Candidates :: load_from_state ( state) ?;
242+ if candidates. get_candidate ( next_delegatee) . is_none ( ) {
243+ return Err ( RuntimeError :: FailedToHandleCustomAction ( "Can delegate to who is a candidate" . into ( ) ) . into ( ) )
244+ }
245+
246+ let banned = Banned :: load_from_state ( state) ?;
247+ let jailed = Jail :: load_from_state ( state) ?;
248+ assert ! ( !banned. is_banned( & next_delegatee) , "A candidate must not be banned" ) ;
249+ assert_eq ! ( None , jailed. get_prisoner( next_delegatee) , "A candidate must not be jailed" ) ;
250+
251+ let delegator = StakeAccount :: load_from_state ( state, fee_payer) ?;
252+ let mut delegation = Delegation :: load_from_state ( state, & fee_payer) ?;
253+
254+ delegation. subtract_quantity ( * prev_delegatee, quantity) ?;
255+ delegation. add_quantity ( * next_delegatee, quantity) ?;
256+
257+ delegation. save_to_state ( state) ?;
258+ delegator. save_to_state ( state) ?;
259+
260+ ctrace ! (
261+ ENGINE ,
262+ "Redelegated CCS. delegator: {}, prev_delegatee: {}, next_delegatee: {}, quantity: {}" ,
263+ fee_payer,
264+ prev_delegatee,
265+ next_delegatee,
266+ quantity
267+ ) ;
268+ Ok ( ( ) )
269+ }
270+
229271fn self_nominate (
230272 state : & mut TopLevelState ,
231273 fee_payer : & Address ,
@@ -916,6 +958,269 @@ mod tests {
916958 assert_eq ! ( state. action_data( & get_delegation_key( & delegator) ) . unwrap( ) , None ) ;
917959 }
918960
961+ #[ test]
962+ fn can_redelegate_tokens ( ) {
963+ let prev_delegatee_pubkey = Public :: random ( ) ;
964+ let prev_delegatee = public_to_address ( & prev_delegatee_pubkey) ;
965+ let next_delegatee_pubkey = Public :: random ( ) ;
966+ let next_delegatee = public_to_address ( & next_delegatee_pubkey) ;
967+ let delegator_pubkey = Public :: random ( ) ;
968+ let delegator = public_to_address ( & delegator_pubkey) ;
969+
970+ let mut state = helpers:: get_temp_state ( ) ;
971+ let stake = {
972+ let mut genesis_stakes = HashMap :: new ( ) ;
973+ genesis_stakes. insert ( delegator, 100 ) ;
974+ Stake :: < SoloMessage > :: new ( genesis_stakes)
975+ } ;
976+ stake. init ( & mut state) . unwrap ( ) ;
977+ self_nominate ( & mut state, & prev_delegatee, & prev_delegatee_pubkey, 0 , 0 , 10 , b"" . to_vec ( ) ) . unwrap ( ) ;
978+ self_nominate ( & mut state, & next_delegatee, & next_delegatee_pubkey, 0 , 0 , 10 , b"" . to_vec ( ) ) . unwrap ( ) ;
979+
980+ let action = Action :: < SoloMessage > :: DelegateCCS {
981+ address : prev_delegatee,
982+ quantity : 50 ,
983+ } ;
984+ let result = stake. execute ( & action. rlp_bytes ( ) , & mut state, & delegator, & delegator_pubkey) ;
985+ assert ! ( result. is_ok( ) ) ;
986+
987+ let action = Action :: < SoloMessage > :: Redelegate {
988+ prev_delegatee,
989+ next_delegatee,
990+ quantity : 20 ,
991+ } ;
992+ let result = stake. execute ( & action. rlp_bytes ( ) , & mut state, & delegator, & delegator_pubkey) ;
993+ assert_eq ! ( Ok ( ( ) ) , result) ;
994+
995+ let delegator_account = StakeAccount :: load_from_state ( & state, & delegator) . unwrap ( ) ;
996+ let delegation = Delegation :: load_from_state ( & state, & delegator) . unwrap ( ) ;
997+ assert_eq ! ( delegator_account. balance, 100 - 50 ) ;
998+ assert_eq ! ( delegation. iter( ) . count( ) , 2 ) ;
999+ assert_eq ! ( delegation. get_quantity( & prev_delegatee) , 50 - 20 ) ;
1000+ assert_eq ! ( delegation. get_quantity( & next_delegatee) , 20 ) ;
1001+ }
1002+
1003+ #[ test]
1004+ fn cannot_redelegate_more_than_delegated_tokens ( ) {
1005+ let prev_delegatee_pubkey = Public :: random ( ) ;
1006+ let prev_delegatee = public_to_address ( & prev_delegatee_pubkey) ;
1007+ let next_delegatee_pubkey = Public :: random ( ) ;
1008+ let next_delegatee = public_to_address ( & next_delegatee_pubkey) ;
1009+ let delegator_pubkey = Public :: random ( ) ;
1010+ let delegator = public_to_address ( & delegator_pubkey) ;
1011+
1012+ let mut state = helpers:: get_temp_state ( ) ;
1013+ let stake = {
1014+ let mut genesis_stakes = HashMap :: new ( ) ;
1015+ genesis_stakes. insert ( delegator, 100 ) ;
1016+ Stake :: < SoloMessage > :: new ( genesis_stakes)
1017+ } ;
1018+ stake. init ( & mut state) . unwrap ( ) ;
1019+ self_nominate ( & mut state, & prev_delegatee, & prev_delegatee_pubkey, 0 , 0 , 10 , b"" . to_vec ( ) ) . unwrap ( ) ;
1020+ self_nominate ( & mut state, & next_delegatee, & next_delegatee_pubkey, 0 , 0 , 10 , b"" . to_vec ( ) ) . unwrap ( ) ;
1021+
1022+ let action = Action :: < SoloMessage > :: DelegateCCS {
1023+ address : prev_delegatee,
1024+ quantity : 50 ,
1025+ } ;
1026+ let result = stake. execute ( & action. rlp_bytes ( ) , & mut state, & delegator, & delegator_pubkey) ;
1027+ assert ! ( result. is_ok( ) ) ;
1028+
1029+ let action = Action :: < SoloMessage > :: Redelegate {
1030+ prev_delegatee,
1031+ next_delegatee,
1032+ quantity : 70 ,
1033+ } ;
1034+ let result = stake. execute ( & action. rlp_bytes ( ) , & mut state, & delegator, & delegator_pubkey) ;
1035+ assert ! ( result. is_err( ) ) ;
1036+
1037+ let delegator_account = StakeAccount :: load_from_state ( & state, & delegator) . unwrap ( ) ;
1038+ let delegation = Delegation :: load_from_state ( & state, & delegator) . unwrap ( ) ;
1039+ assert_eq ! ( delegator_account. balance, 100 - 50 ) ;
1040+ assert_eq ! ( delegation. iter( ) . count( ) , 1 ) ;
1041+ assert_eq ! ( delegation. get_quantity( & prev_delegatee) , 50 ) ;
1042+ assert_eq ! ( delegation. get_quantity( & next_delegatee) , 0 ) ;
1043+ }
1044+
1045+ #[ test]
1046+ fn redelegate_all_should_clear_state ( ) {
1047+ let prev_delegatee_pubkey = Public :: random ( ) ;
1048+ let prev_delegatee = public_to_address ( & prev_delegatee_pubkey) ;
1049+ let next_delegatee_pubkey = Public :: random ( ) ;
1050+ let next_delegatee = public_to_address ( & next_delegatee_pubkey) ;
1051+ let delegator_pubkey = Public :: random ( ) ;
1052+ let delegator = public_to_address ( & delegator_pubkey) ;
1053+
1054+ let mut state = helpers:: get_temp_state ( ) ;
1055+ let stake = {
1056+ let mut genesis_stakes = HashMap :: new ( ) ;
1057+ genesis_stakes. insert ( delegator, 100 ) ;
1058+ Stake :: < SoloMessage > :: new ( genesis_stakes)
1059+ } ;
1060+ stake. init ( & mut state) . unwrap ( ) ;
1061+ self_nominate ( & mut state, & prev_delegatee, & prev_delegatee_pubkey, 0 , 0 , 10 , b"" . to_vec ( ) ) . unwrap ( ) ;
1062+ self_nominate ( & mut state, & next_delegatee, & next_delegatee_pubkey, 0 , 0 , 10 , b"" . to_vec ( ) ) . unwrap ( ) ;
1063+
1064+ let action = Action :: < SoloMessage > :: DelegateCCS {
1065+ address : prev_delegatee,
1066+ quantity : 50 ,
1067+ } ;
1068+ let result = stake. execute ( & action. rlp_bytes ( ) , & mut state, & delegator, & delegator_pubkey) ;
1069+ assert ! ( result. is_ok( ) ) ;
1070+
1071+ let action = Action :: < SoloMessage > :: Redelegate {
1072+ prev_delegatee,
1073+ next_delegatee,
1074+ quantity : 50 ,
1075+ } ;
1076+ let result = stake. execute ( & action. rlp_bytes ( ) , & mut state, & delegator, & delegator_pubkey) ;
1077+ assert_eq ! ( Ok ( ( ) ) , result) ;
1078+
1079+ let delegator_account = StakeAccount :: load_from_state ( & state, & delegator) . unwrap ( ) ;
1080+ let delegation = Delegation :: load_from_state ( & state, & delegator) . unwrap ( ) ;
1081+ assert_eq ! ( delegator_account. balance, 50 ) ;
1082+ assert_eq ! ( delegation. iter( ) . count( ) , 1 ) ;
1083+ assert_eq ! ( delegation. get_quantity( & prev_delegatee) , 0 ) ;
1084+ assert_eq ! ( delegation. get_quantity( & next_delegatee) , 50 ) ;
1085+ }
1086+
1087+ #[ test]
1088+ fn redelegate_only_to_candidate ( ) {
1089+ let prev_delegatee_pubkey = Public :: random ( ) ;
1090+ let prev_delegatee = public_to_address ( & prev_delegatee_pubkey) ;
1091+ let next_delegatee_pubkey = Public :: random ( ) ;
1092+ let next_delegatee = public_to_address ( & next_delegatee_pubkey) ;
1093+ let delegator_pubkey = Public :: random ( ) ;
1094+ let delegator = public_to_address ( & delegator_pubkey) ;
1095+
1096+ let mut state = helpers:: get_temp_state ( ) ;
1097+ let stake = {
1098+ let mut genesis_stakes = HashMap :: new ( ) ;
1099+ genesis_stakes. insert ( delegator, 100 ) ;
1100+ Stake :: < SoloMessage > :: new ( genesis_stakes)
1101+ } ;
1102+ stake. init ( & mut state) . unwrap ( ) ;
1103+
1104+ self_nominate ( & mut state, & prev_delegatee, & prev_delegatee_pubkey, 0 , 0 , 10 , b"" . to_vec ( ) ) . unwrap ( ) ;
1105+
1106+ let action = Action :: < SoloMessage > :: DelegateCCS {
1107+ address : prev_delegatee,
1108+ quantity : 40 ,
1109+ } ;
1110+ let result = stake. execute ( & action. rlp_bytes ( ) , & mut state, & delegator, & delegator_pubkey) ;
1111+ assert ! ( result. is_ok( ) ) ;
1112+
1113+ let action = Action :: < SoloMessage > :: Redelegate {
1114+ prev_delegatee,
1115+ next_delegatee,
1116+ quantity : 50 ,
1117+ } ;
1118+ let result = stake. execute ( & action. rlp_bytes ( ) , & mut state, & delegator, & delegator_pubkey) ;
1119+ assert ! ( result. is_err( ) ) ;
1120+ }
1121+
1122+ #[ test]
1123+ fn cannot_redelegate_to_banned_account ( ) {
1124+ let informant_pubkey = Public :: random ( ) ;
1125+ let criminal_pubkey = Public :: random ( ) ;
1126+ let delegator_pubkey = Public :: random ( ) ;
1127+ let criminal = public_to_address ( & criminal_pubkey) ;
1128+ let delegator = public_to_address ( & delegator_pubkey) ;
1129+ let prev_delegatee_pubkey = Public :: random ( ) ;
1130+ let prev_delegatee = public_to_address ( & prev_delegatee_pubkey) ;
1131+
1132+ let mut state = helpers:: get_temp_state ( ) ;
1133+ state. add_balance ( & criminal, 1000 ) . unwrap ( ) ;
1134+
1135+ let stake = {
1136+ let mut genesis_stakes = HashMap :: new ( ) ;
1137+ genesis_stakes. insert ( delegator, 100 ) ;
1138+ Stake :: < SoloMessage > :: new ( genesis_stakes)
1139+ } ;
1140+ stake. init ( & mut state) . unwrap ( ) ;
1141+ self_nominate ( & mut state, & prev_delegatee, & prev_delegatee_pubkey, 0 , 0 , 10 , b"" . to_vec ( ) ) . unwrap ( ) ;
1142+ self_nominate ( & mut state, & criminal, & criminal_pubkey, 100 , 0 , 10 , b"" . to_vec ( ) ) . unwrap ( ) ;
1143+
1144+ let action = Action :: < SoloMessage > :: DelegateCCS {
1145+ address : criminal,
1146+ quantity : 40 ,
1147+ } ;
1148+ stake. execute ( & action. rlp_bytes ( ) , & mut state, & delegator, & delegator_pubkey) . unwrap ( ) ;
1149+ let action = Action :: < SoloMessage > :: DelegateCCS {
1150+ address : prev_delegatee,
1151+ quantity : 40 ,
1152+ } ;
1153+ stake. execute ( & action. rlp_bytes ( ) , & mut state, & delegator, & delegator_pubkey) . unwrap ( ) ;
1154+
1155+ let candidates = Candidates :: load_from_state ( & state) . unwrap ( ) ;
1156+ assert_eq ! ( candidates. len( ) , 2 ) ;
1157+
1158+ assert_eq ! ( Ok ( ( ) ) , ban( & mut state, & informant_pubkey, criminal) ) ;
1159+
1160+ let banned = Banned :: load_from_state ( & state) . unwrap ( ) ;
1161+ assert ! ( banned. is_banned( & criminal) ) ;
1162+
1163+ let candidates = Candidates :: load_from_state ( & state) . unwrap ( ) ;
1164+ assert_eq ! ( candidates. len( ) , 1 ) ;
1165+
1166+ let action = Action :: < SoloMessage > :: Redelegate {
1167+ prev_delegatee,
1168+ next_delegatee : criminal,
1169+ quantity : 40 ,
1170+ } ;
1171+ let result = stake. execute ( & action. rlp_bytes ( ) , & mut state, & delegator, & delegator_pubkey) ;
1172+ assert ! ( result. is_err( ) ) ;
1173+ }
1174+
1175+ #[ test]
1176+ fn cannot_redelegate_to_jailed_account ( ) {
1177+ let jail_pubkey = Public :: random ( ) ;
1178+ let jail_address = public_to_address ( & jail_pubkey) ;
1179+ let prev_delegatee_pubkey = Public :: random ( ) ;
1180+ let prev_delegatee = public_to_address ( & prev_delegatee_pubkey) ;
1181+ let delegator_pubkey = Public :: random ( ) ;
1182+ let delegator = public_to_address ( & delegator_pubkey) ;
1183+
1184+ let mut state = helpers:: get_temp_state ( ) ;
1185+ state. add_balance ( & jail_address, 1000 ) . unwrap ( ) ;
1186+
1187+ let stake = {
1188+ let mut genesis_stakes = HashMap :: new ( ) ;
1189+ genesis_stakes. insert ( delegator, 100 ) ;
1190+ Stake :: < SoloMessage > :: new ( genesis_stakes)
1191+ } ;
1192+ stake. init ( & mut state) . unwrap ( ) ;
1193+ self_nominate ( & mut state, & prev_delegatee, & prev_delegatee_pubkey, 0 , 0 , 10 , b"" . to_vec ( ) ) . unwrap ( ) ;
1194+
1195+ let deposit = 200 ;
1196+ self_nominate ( & mut state, & jail_address, & jail_pubkey, deposit, 0 , 5 , b"" . to_vec ( ) ) . unwrap ( ) ;
1197+
1198+ let action = Action :: < SoloMessage > :: DelegateCCS {
1199+ address : prev_delegatee,
1200+ quantity : 40 ,
1201+ } ;
1202+ stake. execute ( & action. rlp_bytes ( ) , & mut state, & delegator, & delegator_pubkey) . unwrap ( ) ;
1203+
1204+ let candidates = Candidates :: load_from_state ( & state) . unwrap ( ) ;
1205+ assert_eq ! ( candidates. len( ) , 2 ) ;
1206+
1207+ let custody_until = 10 ;
1208+ let released_at = 20 ;
1209+ let result = jail ( & mut state, & [ jail_address] , custody_until, released_at) ;
1210+ assert ! ( result. is_ok( ) ) ;
1211+
1212+ let candidates = Candidates :: load_from_state ( & state) . unwrap ( ) ;
1213+ assert_eq ! ( candidates. len( ) , 1 ) ;
1214+
1215+ let action = Action :: < SoloMessage > :: Redelegate {
1216+ prev_delegatee,
1217+ next_delegatee : jail_address,
1218+ quantity : 40 ,
1219+ } ;
1220+ let result = stake. execute ( & action. rlp_bytes ( ) , & mut state, & delegator, & delegator_pubkey) ;
1221+ assert ! ( result. is_err( ) ) ;
1222+ }
1223+
9191224 #[ test]
9201225 fn self_nominate_deposit_test ( ) {
9211226 let address_pubkey = Public :: random ( ) ;
0 commit comments