1414// You should have received a copy of the GNU Affero General Public License
1515// along with this program. If not, see <https://www.gnu.org/licenses/>.
1616
17+ use std:: sync:: Arc ;
18+
1719use ccrypto:: Blake ;
18- use ckey:: { recover, Address , Signature } ;
20+ use ckey:: { recover, Address , Public , Signature } ;
21+ use client:: ConsensusClient ;
22+ use consensus:: stake:: get_validators;
23+ use consensus:: vote_collector:: Message ;
1924use ctypes:: errors:: SyntaxError ;
2025use ctypes:: CommonParams ;
2126use primitives:: { Bytes , H256 } ;
@@ -25,10 +30,11 @@ const ACTION_TAG_TRANSFER_CCS: u8 = 1;
2530const ACTION_TAG_DELEGATE_CCS : u8 = 2 ;
2631const ACTION_TAG_REVOKE : u8 = 3 ;
2732const ACTION_TAG_SELF_NOMINATE : u8 = 4 ;
33+ const ACTION_TAG_REPORT_DOUBLE_VOTE : u8 = 5 ;
2834const ACTION_TAG_CHANGE_PARAMS : u8 = 0xFF ;
2935
3036#[ derive( Debug , PartialEq ) ]
31- pub enum Action {
37+ pub enum Action < M : Message > {
3238 TransferCCS {
3339 address : Address ,
3440 quantity : u64 ,
@@ -50,10 +56,18 @@ pub enum Action {
5056 params : Box < CommonParams > ,
5157 signatures : Vec < Signature > ,
5258 } ,
59+ ReportDoubleVote {
60+ message1 : M ,
61+ message2 : M ,
62+ } ,
5363}
5464
55- impl Action {
56- pub fn verify ( & self , current_params : & CommonParams ) -> Result < ( ) , SyntaxError > {
65+ impl < M : Message > Action < M > {
66+ pub fn verify (
67+ & self ,
68+ current_params : & CommonParams ,
69+ client : Option < Arc < ConsensusClient > > ,
70+ ) -> Result < ( ) , SyntaxError > {
5771 match self {
5872 Action :: TransferCCS {
5973 ..
@@ -89,7 +103,7 @@ impl Action {
89103 ) ) )
90104 }
91105 params. verify ( ) . map_err ( SyntaxError :: InvalidCustomAction ) ?;
92- let action = Action :: ChangeParams {
106+ let action = Action :: < M > :: ChangeParams {
93107 metadata_seq : * metadata_seq,
94108 params : params. clone ( ) ,
95109 signatures : vec ! [ ] ,
@@ -102,12 +116,71 @@ impl Action {
102116 } ) ?;
103117 }
104118 }
119+ Action :: ReportDoubleVote {
120+ message1,
121+ message2,
122+ } => {
123+ if message1 == message2 {
124+ return Err ( SyntaxError :: InvalidCustomAction ( String :: from ( "messages are duplicated" ) ) )
125+ }
126+ if message1. round ( ) != message2. round ( ) {
127+ return Err ( SyntaxError :: InvalidCustomAction ( String :: from (
128+ "The messages are from two different voting rounds" ,
129+ ) ) )
130+ }
131+
132+ let signer_idx1 = message1. signer_index ( ) ;
133+ let signer_idx2 = message2. signer_index ( ) ;
134+
135+ // we have checked message1.round() == message2.round() so we can certain that
136+ // message1.height() == message2.height(). So symmetry beaking does not occur here.
137+ let signed_block_height = message1. height ( ) ;
138+ let client = client. expect ( "Client should be initialized" ) ;
139+ let parent_block_hash = client
140+ . block_header ( & signed_block_height. into ( ) )
141+ . ok_or_else ( || {
142+ SyntaxError :: InvalidCustomAction ( format ! (
143+ "Cannot get header from the height {}" ,
144+ signed_block_height
145+ ) )
146+ } ) ?
147+ . parent_hash ( ) ;
148+
149+ let parent_state = client. state_at ( parent_block_hash. into ( ) ) . ok_or_else ( || {
150+ SyntaxError :: InvalidCustomAction ( String :: from (
151+ "Cannot read state from the given message's parent hash" ,
152+ ) )
153+ } ) ?;
154+ let signers_vec: Vec < Public > = get_validators ( & parent_state)
155+ . map ( |validators| validators. into_iter ( ) . map ( |val| * val. pubkey ( ) ) . collect ( ) )
156+ . map_err ( |_| {
157+ SyntaxError :: InvalidCustomAction ( String :: from ( "Cannot get validators from parent_state" ) )
158+ } ) ?;
159+
160+ let signer1 = signers_vec. get ( signer_idx1) . ok_or_else ( || {
161+ SyntaxError :: InvalidCustomAction ( String :: from ( "Invalid signer index in message1" ) )
162+ } ) ?;
163+ let signer2 = signers_vec. get ( signer_idx2) . ok_or_else ( || {
164+ SyntaxError :: InvalidCustomAction ( String :: from ( "Invalid signer index in message2" ) )
165+ } ) ?;
166+
167+ if signer1 != signer2 {
168+ return Err ( SyntaxError :: InvalidCustomAction ( format ! (
169+ "Two messages are signed by different signers: {}, {}" ,
170+ signer1, signer2
171+ ) ) )
172+ }
173+
174+ if message1. verify ( signer1) != Ok ( true ) || message2. verify ( signer2) != Ok ( true ) {
175+ return Err ( SyntaxError :: InvalidCustomAction ( String :: from ( "Schnorr signature verification fails" ) ) )
176+ }
177+ }
105178 }
106179 Ok ( ( ) )
107180 }
108181}
109182
110- impl Encodable for Action {
183+ impl < M : Message > Encodable for Action < M > {
111184 fn rlp_append ( & self , s : & mut RlpStream ) {
112185 match self {
113186 Action :: TransferCCS {
@@ -147,11 +220,17 @@ impl Encodable for Action {
147220 s. append ( signature) ;
148221 }
149222 }
223+ Action :: ReportDoubleVote {
224+ message1,
225+ message2,
226+ } => {
227+ s. begin_list ( 3 ) . append ( & ACTION_TAG_REPORT_DOUBLE_VOTE ) . append ( message1) . append ( message2) ;
228+ }
150229 } ;
151230 }
152231}
153232
154- impl Decodable for Action {
233+ impl < M : Message > Decodable for Action < M > {
155234 fn decode ( rlp : & UntrustedRlp ) -> Result < Self , DecoderError > {
156235 let tag = rlp. val_at ( 0 ) ?;
157236 match tag {
@@ -224,6 +303,21 @@ impl Decodable for Action {
224303 signatures,
225304 } )
226305 }
306+ ACTION_TAG_REPORT_DOUBLE_VOTE => {
307+ let item_count = rlp. item_count ( ) ?;
308+ if item_count != 3 {
309+ return Err ( DecoderError :: RlpIncorrectListLen {
310+ expected : 3 ,
311+ got : item_count,
312+ } )
313+ }
314+ let message1 = rlp. val_at ( 1 ) ?;
315+ let message2 = rlp. val_at ( 2 ) ?;
316+ Ok ( Action :: ReportDoubleVote {
317+ message1,
318+ message2,
319+ } )
320+ }
227321 _ => Err ( DecoderError :: Custom ( "Unexpected Tendermint Stake Action Type" ) ) ,
228322 }
229323 }
@@ -247,7 +341,7 @@ mod tests {
247341 expected: 4 ,
248342 got: 3 ,
249343 } ) ,
250- UntrustedRlp :: new( & rlp:: encode( & action) ) . as_val:: <Action >( )
344+ UntrustedRlp :: new( & rlp:: encode( & action) ) . as_val:: <Action >:: <_> ( )
251345 ) ;
252346 }
253347
0 commit comments