@@ -29,7 +29,7 @@ use crate::persistence::ContactStoreApi;
29
29
use crate :: service:: company_service:: Company ;
30
30
use crate :: util:: BcrKeys ;
31
31
use crate :: web:: data:: {
32
- BillCombinedBitcoinKey , BillsFilterRole , File , LightSignedBy , PastEndorsee ,
32
+ BillCombinedBitcoinKey , BillsFilterRole , Endorsement , File , LightSignedBy , PastEndorsee ,
33
33
} ;
34
34
use crate :: web:: ErrorResponse ;
35
35
use crate :: { dht, external, persistence, util} ;
@@ -522,6 +522,13 @@ pub trait BillServiceApi: Send + Sync {
522
522
bill_id : & str ,
523
523
current_identity_node_id : & str ,
524
524
) -> Result < Vec < PastEndorsee > > ;
525
+
526
+ /// Returns all endorsements of the bill
527
+ async fn get_endorsements (
528
+ & self ,
529
+ bill_id : & str ,
530
+ current_identity_node_id : & str ,
531
+ ) -> Result < Vec < Endorsement > > ;
525
532
}
526
533
527
534
/// The bill service is responsible for all bill-related logic and for syncing them with the dht data.
@@ -920,6 +927,7 @@ impl BillService {
920
927
let first_version_bill = chain. get_first_version_bill ( & bill_keys) ?;
921
928
let time_of_drawing = first_version_bill. signing_timestamp ;
922
929
let bill_participants = chain. get_all_nodes_from_bill ( & bill_keys) ?;
930
+ let endorsements_count = chain. get_endorsements_count ( ) ;
923
931
924
932
let mut in_recourse = false ;
925
933
let mut link_to_pay_recourse = "" . to_string ( ) ;
@@ -1071,6 +1079,7 @@ impl BillService {
1071
1079
files : bill. files ,
1072
1080
active_notification,
1073
1081
bill_participants,
1082
+ endorsements_count,
1074
1083
} )
1075
1084
}
1076
1085
@@ -1398,6 +1407,11 @@ impl BillService {
1398
1407
1399
1408
let mut found_last_endorsing_block_for_node = false ;
1400
1409
for block in chain. blocks ( ) . iter ( ) . rev ( ) {
1410
+ // we ignore recourse blocks, since we're only interested in previous endorsees before
1411
+ // recourse
1412
+ if block. op_code == BillOpCode :: Recourse {
1413
+ continue ;
1414
+ }
1401
1415
if let Ok ( Some ( holder_from_block) ) = block. get_holder_from_block ( bill_keys) {
1402
1416
// first, we search for the last non-recourse block in which we became holder
1403
1417
if holder_from_block. holder . node_id == * current_identity_node_id
@@ -1415,7 +1429,7 @@ impl BillService {
1415
1429
. or_insert ( PastEndorsee {
1416
1430
pay_to_the_order_of : holder_from_block. holder . clone ( ) . into ( ) ,
1417
1431
signed : LightSignedBy {
1418
- data : holder_from_block. signer . into ( ) ,
1432
+ data : holder_from_block. signer . clone ( ) . into ( ) ,
1419
1433
signatory : holder_from_block. signatory . map ( |s| {
1420
1434
LightIdentityPublicData {
1421
1435
name : s. name ,
@@ -1424,6 +1438,7 @@ impl BillService {
1424
1438
} ) ,
1425
1439
} ,
1426
1440
signing_timestamp : block. timestamp ,
1441
+ signing_address : holder_from_block. signer . postal_address ,
1427
1442
} ) ;
1428
1443
}
1429
1444
}
@@ -1438,7 +1453,7 @@ impl BillService {
1438
1453
. or_insert ( PastEndorsee {
1439
1454
pay_to_the_order_of : first_version_bill. drawer . clone ( ) . into ( ) ,
1440
1455
signed : LightSignedBy {
1441
- data : first_version_bill. drawer . into ( ) ,
1456
+ data : first_version_bill. drawer . clone ( ) . into ( ) ,
1442
1457
signatory : first_version_bill
1443
1458
. signatory
1444
1459
. map ( |s| LightIdentityPublicData {
@@ -1447,6 +1462,7 @@ impl BillService {
1447
1462
} ) ,
1448
1463
} ,
1449
1464
signing_timestamp : first_version_bill. signing_timestamp ,
1465
+ signing_address : first_version_bill. drawer . postal_address ,
1450
1466
} ) ;
1451
1467
}
1452
1468
@@ -3052,6 +3068,55 @@ impl BillServiceApi for BillService {
3052
3068
3053
3069
self . get_past_endorsees_for_bill ( & chain, & bill_keys, current_identity_node_id)
3054
3070
}
3071
+
3072
+ async fn get_endorsements (
3073
+ & self ,
3074
+ bill_id : & str ,
3075
+ current_identity_node_id : & str ,
3076
+ ) -> Result < Vec < Endorsement > > {
3077
+ if !self . store . exists ( bill_id) . await {
3078
+ return Err ( Error :: NotFound ) ;
3079
+ }
3080
+
3081
+ let chain = self . blockchain_store . get_chain ( bill_id) . await ?;
3082
+ let bill_keys = self . store . get_keys ( bill_id) . await ?;
3083
+
3084
+ let bill_participants = chain. get_all_nodes_from_bill ( & bill_keys) ?;
3085
+ // active identity is not part of the bill
3086
+ if !bill_participants
3087
+ . iter ( )
3088
+ . any ( |p| p == current_identity_node_id)
3089
+ {
3090
+ return Err ( Error :: NotFound ) ;
3091
+ }
3092
+
3093
+ let mut result: Vec < Endorsement > = vec ! [ ] ;
3094
+ // iterate from the back to the front, collecting all endorsement blocks
3095
+ for block in chain. blocks ( ) . iter ( ) . rev ( ) {
3096
+ // we ignore issue blocks, since we are only interested in endorsements
3097
+ if block. op_code == BillOpCode :: Issue {
3098
+ continue ;
3099
+ }
3100
+ if let Ok ( Some ( holder_from_block) ) = block. get_holder_from_block ( & bill_keys) {
3101
+ result. push ( Endorsement {
3102
+ pay_to_the_order_of : holder_from_block. holder . clone ( ) . into ( ) ,
3103
+ signed : LightSignedBy {
3104
+ data : holder_from_block. signer . clone ( ) . into ( ) ,
3105
+ signatory : holder_from_block
3106
+ . signatory
3107
+ . map ( |s| LightIdentityPublicData {
3108
+ name : s. name ,
3109
+ node_id : s. node_id ,
3110
+ } ) ,
3111
+ } ,
3112
+ signing_timestamp : block. timestamp ,
3113
+ signing_address : holder_from_block. signer . postal_address ,
3114
+ } ) ;
3115
+ }
3116
+ }
3117
+
3118
+ Ok ( result)
3119
+ }
3055
3120
}
3056
3121
3057
3122
#[ derive( Debug , Clone ) ]
@@ -3164,6 +3229,7 @@ pub struct BitcreditBillToReturn {
3164
3229
/// The currently active notification for this bill if any
3165
3230
pub active_notification : Option < Notification > ,
3166
3231
pub bill_participants : Vec < String > ,
3232
+ pub endorsements_count : u64 ,
3167
3233
}
3168
3234
3169
3235
impl BitcreditBillToReturn {
@@ -6545,6 +6611,193 @@ pub mod tests {
6545
6611
. expect ( "block could not be created" )
6546
6612
}
6547
6613
6614
+ #[ tokio:: test]
6615
+ async fn get_endorsements_baseline ( ) {
6616
+ let (
6617
+ mut storage,
6618
+ mut chain_storage,
6619
+ identity_storage,
6620
+ file_upload_storage,
6621
+ identity_chain_store,
6622
+ company_chain_store,
6623
+ contact_storage,
6624
+ company_storage,
6625
+ ) = get_storages ( ) ;
6626
+ let identity = get_baseline_identity ( ) ;
6627
+ let mut bill = get_baseline_bill ( "1234" ) ;
6628
+ bill. drawer = IdentityPublicData :: new ( identity. identity . clone ( ) ) . unwrap ( ) ;
6629
+
6630
+ storage. expect_exists ( ) . returning ( |_| true ) ;
6631
+ storage. expect_get_keys ( ) . returning ( |_| {
6632
+ Ok ( BillKeys {
6633
+ private_key : TEST_PRIVATE_KEY_SECP . to_owned ( ) ,
6634
+ public_key : TEST_PUB_KEY_SECP . to_owned ( ) ,
6635
+ } )
6636
+ } ) ;
6637
+ chain_storage
6638
+ . expect_get_chain ( )
6639
+ . returning ( move |_| Ok ( get_genesis_chain ( Some ( bill. clone ( ) ) ) ) ) ;
6640
+
6641
+ let service = get_service (
6642
+ storage,
6643
+ chain_storage,
6644
+ identity_storage,
6645
+ file_upload_storage,
6646
+ identity_chain_store,
6647
+ company_chain_store,
6648
+ contact_storage,
6649
+ company_storage,
6650
+ ) ;
6651
+
6652
+ let res = service
6653
+ . get_endorsements ( "1234" , & identity. identity . node_id )
6654
+ . await ;
6655
+ assert ! ( res. is_ok( ) ) ;
6656
+ assert_eq ! ( res. as_ref( ) . unwrap( ) . len( ) , 0 ) ;
6657
+ }
6658
+
6659
+ #[ tokio:: test]
6660
+ async fn get_endorsements_multi ( ) {
6661
+ let (
6662
+ mut storage,
6663
+ mut chain_storage,
6664
+ identity_storage,
6665
+ file_upload_storage,
6666
+ identity_chain_store,
6667
+ company_chain_store,
6668
+ contact_storage,
6669
+ company_storage,
6670
+ ) = get_storages ( ) ;
6671
+ let identity = get_baseline_identity ( ) ;
6672
+ let mut bill = get_baseline_bill ( "1234" ) ;
6673
+ let drawer = IdentityPublicData :: new_only_node_id ( BcrKeys :: new ( ) . get_public_key ( ) ) ;
6674
+ let mint_endorsee = IdentityPublicData :: new_only_node_id ( BcrKeys :: new ( ) . get_public_key ( ) ) ;
6675
+ let endorse_endorsee =
6676
+ IdentityPublicData :: new_only_node_id ( BcrKeys :: new ( ) . get_public_key ( ) ) ;
6677
+ let sell_endorsee = IdentityPublicData :: new_only_node_id ( BcrKeys :: new ( ) . get_public_key ( ) ) ;
6678
+
6679
+ bill. drawer = drawer. clone ( ) ;
6680
+ bill. drawee = IdentityPublicData :: new_only_node_id ( BcrKeys :: new ( ) . get_public_key ( ) ) ;
6681
+ bill. payee = IdentityPublicData :: new ( get_baseline_identity ( ) . identity ) . unwrap ( ) ;
6682
+
6683
+ storage. expect_exists ( ) . returning ( |_| true ) ;
6684
+ storage. expect_get_keys ( ) . returning ( |_| {
6685
+ Ok ( BillKeys {
6686
+ private_key : TEST_PRIVATE_KEY_SECP . to_owned ( ) ,
6687
+ public_key : TEST_PUB_KEY_SECP . to_owned ( ) ,
6688
+ } )
6689
+ } ) ;
6690
+
6691
+ let endorse_endorsee_clone = endorse_endorsee. clone ( ) ;
6692
+ let mint_endorsee_clone = mint_endorsee. clone ( ) ;
6693
+ let sell_endorsee_clone = sell_endorsee. clone ( ) ;
6694
+
6695
+ chain_storage. expect_get_chain ( ) . returning ( move |_| {
6696
+ let now = util:: date:: now ( ) . timestamp ( ) as u64 ;
6697
+ let mut chain = get_genesis_chain ( Some ( bill. clone ( ) ) ) ;
6698
+
6699
+ // add endorse block from payee to endorsee
6700
+ let endorse_block = BillBlock :: create_block_for_endorse (
6701
+ "1234" . to_string ( ) ,
6702
+ chain. get_latest_block ( ) ,
6703
+ & BillEndorseBlockData {
6704
+ endorsee : endorse_endorsee. clone ( ) . into ( ) ,
6705
+ // endorsed by payee
6706
+ endorser : IdentityPublicData :: new ( get_baseline_identity ( ) . identity )
6707
+ . unwrap ( )
6708
+ . into ( ) ,
6709
+ signatory : None ,
6710
+ signing_timestamp : now + 1 ,
6711
+ signing_address : PostalAddress :: new_empty ( ) ,
6712
+ } ,
6713
+ & BcrKeys :: from_private_key ( TEST_PRIVATE_KEY_SECP ) . unwrap ( ) ,
6714
+ Some ( & BcrKeys :: from_private_key ( TEST_PRIVATE_KEY_SECP ) . unwrap ( ) ) ,
6715
+ & BcrKeys :: from_private_key ( TEST_PRIVATE_KEY_SECP ) . unwrap ( ) ,
6716
+ now + 1 ,
6717
+ )
6718
+ . unwrap ( ) ;
6719
+ assert ! ( chain. try_add_block( endorse_block) ) ;
6720
+
6721
+ // add sell block from endorsee to sell endorsee
6722
+ let sell_block = BillBlock :: create_block_for_sell (
6723
+ "1234" . to_string ( ) ,
6724
+ chain. get_latest_block ( ) ,
6725
+ & BillSellBlockData {
6726
+ buyer : sell_endorsee. clone ( ) . into ( ) ,
6727
+ // endorsed by endorsee
6728
+ seller : endorse_endorsee. clone ( ) . into ( ) ,
6729
+ currency : "sat" . to_string ( ) ,
6730
+ sum : 15000 ,
6731
+ payment_address : "1234paymentaddress" . to_string ( ) ,
6732
+ signatory : None ,
6733
+ signing_timestamp : now + 2 ,
6734
+ signing_address : PostalAddress :: new_empty ( ) ,
6735
+ } ,
6736
+ & BcrKeys :: from_private_key ( TEST_PRIVATE_KEY_SECP ) . unwrap ( ) ,
6737
+ Some ( & BcrKeys :: from_private_key ( TEST_PRIVATE_KEY_SECP ) . unwrap ( ) ) ,
6738
+ & BcrKeys :: from_private_key ( TEST_PRIVATE_KEY_SECP ) . unwrap ( ) ,
6739
+ now + 2 ,
6740
+ )
6741
+ . unwrap ( ) ;
6742
+ assert ! ( chain. try_add_block( sell_block) ) ;
6743
+
6744
+ // add mint block from sell endorsee to mint endorsee
6745
+ let mint_block = BillBlock :: create_block_for_mint (
6746
+ "1234" . to_string ( ) ,
6747
+ chain. get_latest_block ( ) ,
6748
+ & BillMintBlockData {
6749
+ endorsee : mint_endorsee. clone ( ) . into ( ) ,
6750
+ // endorsed by sell endorsee
6751
+ endorser : sell_endorsee. clone ( ) . into ( ) ,
6752
+ currency : "sat" . to_string ( ) ,
6753
+ sum : 15000 ,
6754
+ signatory : None ,
6755
+ signing_timestamp : now + 3 ,
6756
+ signing_address : PostalAddress :: new_empty ( ) ,
6757
+ } ,
6758
+ & BcrKeys :: from_private_key ( TEST_PRIVATE_KEY_SECP ) . unwrap ( ) ,
6759
+ Some ( & BcrKeys :: from_private_key ( TEST_PRIVATE_KEY_SECP ) . unwrap ( ) ) ,
6760
+ & BcrKeys :: from_private_key ( TEST_PRIVATE_KEY_SECP ) . unwrap ( ) ,
6761
+ now + 3 ,
6762
+ )
6763
+ . unwrap ( ) ;
6764
+ assert ! ( chain. try_add_block( mint_block) ) ;
6765
+
6766
+ Ok ( chain)
6767
+ } ) ;
6768
+
6769
+ let service = get_service (
6770
+ storage,
6771
+ chain_storage,
6772
+ identity_storage,
6773
+ file_upload_storage,
6774
+ identity_chain_store,
6775
+ company_chain_store,
6776
+ contact_storage,
6777
+ company_storage,
6778
+ ) ;
6779
+
6780
+ let res = service
6781
+ . get_endorsements ( "1234" , & identity. identity . node_id )
6782
+ . await ;
6783
+ assert ! ( res. is_ok( ) ) ;
6784
+ // with duplicates
6785
+ assert_eq ! ( res. as_ref( ) . unwrap( ) . len( ) , 3 ) ;
6786
+ // mint was last, so it's first
6787
+ assert_eq ! (
6788
+ res. as_ref( ) . unwrap( ) [ 0 ] . pay_to_the_order_of. node_id,
6789
+ mint_endorsee_clone. node_id
6790
+ ) ;
6791
+ assert_eq ! (
6792
+ res. as_ref( ) . unwrap( ) [ 1 ] . pay_to_the_order_of. node_id,
6793
+ sell_endorsee_clone. node_id
6794
+ ) ;
6795
+ assert_eq ! (
6796
+ res. as_ref( ) . unwrap( ) [ 2 ] . pay_to_the_order_of. node_id,
6797
+ endorse_endorsee_clone. node_id
6798
+ ) ;
6799
+ }
6800
+
6548
6801
#[ tokio:: test]
6549
6802
async fn get_past_endorsees_baseline ( ) {
6550
6803
let (
0 commit comments