11use super :: super :: Result ;
22use super :: PaymentInfo ;
33use super :: block:: {
4- BillBlock , BillEndorseBlockData , BillIdentParticipantBlockData , BillIssueBlockData ,
5- BillMintBlockData , BillOfferToSellBlockData , BillParticipantBlockData , BillRecourseBlockData ,
6- BillRequestRecourseBlockData , BillSellBlockData ,
4+ BillAcceptBlockData , BillBlock , BillEndorseBlockData , BillIdentParticipantBlockData ,
5+ BillIssueBlockData , BillMintBlockData , BillOfferToSellBlockData , BillParticipantBlockData ,
6+ BillRecourseBlockData , BillRejectBlockData , BillRequestRecourseBlockData ,
7+ BillRequestToAcceptBlockData , BillRequestToPayBlockData , BillSellBlockData ,
78} ;
89use super :: { BillOpCode , RecourseWaitingForPayment } ;
910use super :: { OfferToSellWaitingForPayment , RecoursePaymentInfo } ;
@@ -15,6 +16,7 @@ use crate::contact::{
1516 BillParticipant , ContactType , LightBillIdentParticipant , LightBillParticipant ,
1617} ;
1718use crate :: util:: { self , BcrKeys } ;
19+ use borsh_derive:: { BorshDeserialize , BorshSerialize } ;
1820use log:: error;
1921use serde:: { Deserialize , Serialize } ;
2022use std:: collections:: HashMap ;
@@ -27,7 +29,13 @@ pub struct BillParties {
2729 pub endorsee : Option < BillParticipantBlockData > ,
2830}
2931
30- #[ derive( Serialize , Deserialize , Debug , Clone ) ]
32+ #[ derive( BorshSerialize , BorshDeserialize , Serialize , Deserialize , Debug , Clone ) ]
33+ pub struct BillBlockPlaintextWrapper {
34+ pub block : BillBlock ,
35+ pub plaintext_data_bytes : Vec < u8 > ,
36+ }
37+
38+ #[ derive( BorshSerialize , BorshDeserialize , Serialize , Deserialize , Debug , Clone ) ]
3139pub struct BillBlockchain {
3240 blocks : Vec < BillBlock > ,
3341}
@@ -701,6 +709,81 @@ impl BillBlockchain {
701709 endorsee : last_endorsee,
702710 } )
703711 }
712+
713+ /// For each block, adds the decrypted and serialized plaintext data next to it
714+ /// This is an expensive operation, since it deserialized, decrypts and reserializes the block data
715+ /// validating the integrity of the data at the end
716+ pub fn get_chain_with_plaintext_block_data (
717+ & self ,
718+ bill_keys : & BillKeys ,
719+ ) -> Result < Vec < BillBlockPlaintextWrapper > > {
720+ let mut result = Vec :: with_capacity ( self . blocks ( ) . len ( ) ) ;
721+ for block in self . blocks . iter ( ) {
722+ let plaintext_data_bytes = match block. op_code ( ) {
723+ BillOpCode :: Issue => {
724+ borsh:: to_vec ( & block. get_decrypted_block :: < BillIssueBlockData > ( bill_keys) ?) ?
725+ }
726+ BillOpCode :: Accept => {
727+ borsh:: to_vec ( & block. get_decrypted_block :: < BillAcceptBlockData > ( bill_keys) ?) ?
728+ }
729+ BillOpCode :: Endorse => {
730+ borsh:: to_vec ( & block. get_decrypted_block :: < BillEndorseBlockData > ( bill_keys) ?) ?
731+ }
732+ BillOpCode :: RequestToAccept => borsh:: to_vec (
733+ & block. get_decrypted_block :: < BillRequestToAcceptBlockData > ( bill_keys) ?,
734+ ) ?,
735+ BillOpCode :: RequestToPay => borsh:: to_vec (
736+ & block. get_decrypted_block :: < BillRequestToPayBlockData > ( bill_keys) ?,
737+ ) ?,
738+ BillOpCode :: OfferToSell => borsh:: to_vec (
739+ & block. get_decrypted_block :: < BillOfferToSellBlockData > ( bill_keys) ?,
740+ ) ?,
741+ BillOpCode :: Sell => {
742+ borsh:: to_vec ( & block. get_decrypted_block :: < BillSellBlockData > ( bill_keys) ?) ?
743+ }
744+ BillOpCode :: Mint => {
745+ borsh:: to_vec ( & block. get_decrypted_block :: < BillMintBlockData > ( bill_keys) ?) ?
746+ }
747+ BillOpCode :: RejectToAccept => {
748+ borsh:: to_vec ( & block. get_decrypted_block :: < BillRejectBlockData > ( bill_keys) ?) ?
749+ }
750+ BillOpCode :: RejectToPay => {
751+ borsh:: to_vec ( & block. get_decrypted_block :: < BillRejectBlockData > ( bill_keys) ?) ?
752+ }
753+ BillOpCode :: RejectToBuy => {
754+ borsh:: to_vec ( & block. get_decrypted_block :: < BillRejectBlockData > ( bill_keys) ?) ?
755+ }
756+ BillOpCode :: RejectToPayRecourse => {
757+ borsh:: to_vec ( & block. get_decrypted_block :: < BillRejectBlockData > ( bill_keys) ?) ?
758+ }
759+ BillOpCode :: RequestRecourse => borsh:: to_vec (
760+ & block. get_decrypted_block :: < BillRequestRecourseBlockData > ( bill_keys) ?,
761+ ) ?,
762+ BillOpCode :: Recourse => {
763+ borsh:: to_vec ( & block. get_decrypted_block :: < BillRecourseBlockData > ( bill_keys) ?) ?
764+ }
765+ } ;
766+
767+ if block. plaintext_hash != util:: sha256_hash ( & plaintext_data_bytes) {
768+ return Err ( Error :: BlockInvalid ) ;
769+ }
770+
771+ result. push ( BillBlockPlaintextWrapper {
772+ block : block. clone ( ) ,
773+ plaintext_data_bytes,
774+ } ) ;
775+ }
776+
777+ // Validate the chain from the wrapper
778+ BillBlockchain :: new_from_blocks (
779+ result
780+ . iter ( )
781+ . map ( |wrapper| wrapper. block . to_owned ( ) )
782+ . collect :: < Vec < BillBlock > > ( ) ,
783+ ) ?;
784+
785+ Ok ( result)
786+ }
704787}
705788
706789#[ cfg( test) ]
@@ -868,7 +951,7 @@ mod tests {
868951 node_id_last_endorsee. clone( ) ,
869952 identity. identity. node_id. to_owned( ) ,
870953 chain. get_first_block( )
871- ) , ) ) ;
954+ ) ) ) ;
872955
873956 let keys = get_bill_keys ( ) ;
874957 let result = chain. get_all_nodes_from_bill ( & keys) ;
@@ -942,4 +1025,41 @@ mod tests {
9421025 assert_eq ! ( result. len( ) , 1 ) ;
9431026 assert_eq ! ( result[ 0 ] . id, 2 ) ;
9441027 }
1028+
1029+ #[ test]
1030+ fn test_get_serialized_chain_with_plaintext ( ) {
1031+ let bill = empty_bitcredit_bill ( ) ;
1032+ let bill_id = bill. id . clone ( ) ;
1033+ let bill_keys = get_bill_keys ( ) ;
1034+ let identity = get_baseline_identity ( ) ;
1035+ let mut chain = BillBlockchain :: new (
1036+ & BillIssueBlockData :: from ( bill, None , 1731593928 ) ,
1037+ identity. key_pair ,
1038+ None ,
1039+ BcrKeys :: from_private_key ( & bill_keys. private_key ) . unwrap ( ) ,
1040+ 1731593928 ,
1041+ )
1042+ . unwrap ( ) ;
1043+ let node_id_last_endorsee =
1044+ NodeId :: new ( BcrKeys :: new ( ) . pub_key ( ) , bitcoin:: Network :: Testnet ) ;
1045+ assert ! ( chain. try_add_block( get_offer_to_sell_block(
1046+ node_id_last_endorsee. clone( ) ,
1047+ identity. identity. node_id. to_owned( ) ,
1048+ chain. get_first_block( )
1049+ ) ) ) ;
1050+
1051+ let chain_with_plaintext = chain. get_chain_with_plaintext_block_data ( & bill_keys) ;
1052+ assert ! ( chain_with_plaintext. is_ok( ) ) ;
1053+ assert_eq ! ( chain_with_plaintext. as_ref( ) . unwrap( ) . len( ) , 2 ) ;
1054+
1055+ let first = chain_with_plaintext. as_ref ( ) . unwrap ( ) [ 0 ] . clone ( ) ;
1056+ let decrypted_block_data: BillIssueBlockData =
1057+ borsh:: from_slice ( & first. plaintext_data_bytes ) . unwrap ( ) ;
1058+ assert_eq ! ( decrypted_block_data. id, bill_id) ;
1059+
1060+ let second = chain_with_plaintext. as_ref ( ) . unwrap ( ) [ 1 ] . clone ( ) ;
1061+ let decrypted_block_data: BillOfferToSellBlockData =
1062+ borsh:: from_slice ( & second. plaintext_data_bytes ) . unwrap ( ) ;
1063+ assert_eq ! ( decrypted_block_data. buyer. node_id( ) , node_id_last_endorsee) ;
1064+ }
9451065}
0 commit comments