From a5a9a44a109930cd46f24b424f86e27e3c35cf12 Mon Sep 17 00:00:00 2001
From: librelois <c@elo.tf>
Date: Thu, 18 Mar 2021 20:31:08 +0100
Subject: [PATCH] [feat] gva:bca: add query SendTxs

---
 Cargo.lock                                    |  2 +
 rust-libs/modules/gva/bca/Cargo.toml          |  1 +
 .../modules/gva/bca/src/exec_req_type.rs      |  2 +
 .../gva/bca/src/exec_req_type/send_txs.rs     | 63 +++++++++++++++++++
 rust-libs/modules/gva/bca/src/lib.rs          |  4 ++
 rust-libs/modules/gva/bca/types/Cargo.toml    |  1 +
 rust-libs/modules/gva/bca/types/src/lib.rs    | 21 ++++++-
 .../modules/gva/bca/types/src/rejected_tx.rs  | 30 +++++++++
 rust-libs/modules/gva/src/lib.rs              |  1 +
 9 files changed, 122 insertions(+), 3 deletions(-)
 create mode 100644 rust-libs/modules/gva/bca/src/exec_req_type/send_txs.rs
 create mode 100644 rust-libs/modules/gva/bca/types/src/rejected_tx.rs

diff --git a/Cargo.lock b/Cargo.lock
index f9ec29096..0e7f2852b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1162,6 +1162,7 @@ dependencies = [
  "duniter-dbs",
  "duniter-gva-db",
  "duniter-gva-dbs-reader",
+ "duniter-mempools",
  "fast-threadpool",
  "futures",
  "mockall",
@@ -1178,6 +1179,7 @@ dependencies = [
  "bincode",
  "dubp",
  "serde",
+ "smallvec",
  "thiserror",
 ]
 
diff --git a/rust-libs/modules/gva/bca/Cargo.toml b/rust-libs/modules/gva/bca/Cargo.toml
index f4f6b1749..1495e533e 100644
--- a/rust-libs/modules/gva/bca/Cargo.toml
+++ b/rust-libs/modules/gva/bca/Cargo.toml
@@ -15,6 +15,7 @@ duniter-bca-types = { path = "types", features = ["duniter"] }
 duniter-dbs = { path = "../../../duniter-dbs" }
 duniter-gva-db = { path = "../db" }
 duniter-gva-dbs-reader = { path = "../dbs-reader" }
+duniter-mempools = { path = "../../../duniter-mempools" }
 fast-threadpool = "0.2.3"
 futures = "0.3.6"
 once_cell = "1.5"
diff --git a/rust-libs/modules/gva/bca/src/exec_req_type.rs b/rust-libs/modules/gva/bca/src/exec_req_type.rs
index 3134f3d3e..bf8e8e255 100644
--- a/rust-libs/modules/gva/bca/src/exec_req_type.rs
+++ b/rust-libs/modules/gva/bca/src/exec_req_type.rs
@@ -15,6 +15,7 @@
 
 mod members_count;
 mod prepare_simple_payment;
+mod send_txs;
 
 use dubp::crypto::keys::KeyPair;
 
@@ -51,5 +52,6 @@ pub(super) async fn execute_req_type(
                 .sign(&challenge),
         }),
         BcaReqTypeV0::Ping => Ok(BcaRespTypeV0::Pong),
+        BcaReqTypeV0::SendTxs(txs) => send_txs::send_txs(bca_executor, txs).await,
     }
 }
diff --git a/rust-libs/modules/gva/bca/src/exec_req_type/send_txs.rs b/rust-libs/modules/gva/bca/src/exec_req_type/send_txs.rs
new file mode 100644
index 000000000..e6a5c25c4
--- /dev/null
+++ b/rust-libs/modules/gva/bca/src/exec_req_type/send_txs.rs
@@ -0,0 +1,63 @@
+//  Copyright (C) 2020 Éloïs SANCHEZ.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+use crate::*;
+use dubp::{crypto::keys::KeyPair, documents::transaction::TransactionDocumentTrait};
+use duniter_bca_types::{
+    rejected_tx::{RejectedTx, RejectedTxReason},
+    Txs,
+};
+
+pub(super) async fn send_txs(
+    bca_executor: &BcaExecutor,
+    txs: Txs,
+) -> Result<BcaRespTypeV0, ExecReqTypeError> {
+    let expected_currency = bca_executor.currency.clone();
+
+    let server_pubkey = bca_executor.self_keypair.public_key();
+    let txs_mempool = bca_executor.txs_mempool;
+
+    let mut rejected_txs = Vec::new();
+    for (i, tx) in txs.into_iter().enumerate() {
+        if let Err(e) = tx.verify(Some(&expected_currency)) {
+            rejected_txs.push(RejectedTx {
+                tx_index: i as u16,
+                reason: RejectedTxReason::InvalidTx(e.to_string()),
+            });
+        } else if let Err(rejected_tx) = bca_executor
+            .dbs_pool
+            .execute(move |dbs| {
+                txs_mempool
+                    .add_pending_tx(&dbs.bc_db_ro, server_pubkey, &dbs.txs_mp_db, &tx)
+                    .map_err(|e| RejectedTx {
+                        tx_index: i as u16,
+                        reason: match e {
+                            duniter_mempools::TxMpError::Db(e) => {
+                                RejectedTxReason::DbError(e.to_string())
+                            }
+                            duniter_mempools::TxMpError::Full => RejectedTxReason::MempoolFull,
+                            duniter_mempools::TxMpError::TxAlreadyWritten => {
+                                RejectedTxReason::TxAlreadyWritten
+                            }
+                        },
+                    })
+            })
+            .await?
+        {
+            rejected_txs.push(rejected_tx);
+        }
+    }
+    Ok(BcaRespTypeV0::RejectedTxs(rejected_txs))
+}
diff --git a/rust-libs/modules/gva/bca/src/lib.rs b/rust-libs/modules/gva/bca/src/lib.rs
index 91a8ba1b6..d031c7b0b 100644
--- a/rust-libs/modules/gva/bca/src/lib.rs
+++ b/rust-libs/modules/gva/bca/src/lib.rs
@@ -54,6 +54,7 @@ pub fn set_bca_executor(
     dbs_reader: DbsReader,
     self_keypair: Ed25519KeyPair,
     software_version: &'static str,
+    txs_mempool: duniter_mempools::TxsMempool,
 ) {
     BCA_EXECUTOR
         .set(BcaExecutor {
@@ -62,6 +63,7 @@ pub fn set_bca_executor(
             dbs_reader,
             self_keypair,
             software_version,
+            txs_mempool,
         })
         .unwrap_or_else(|_| panic!("BCA_EXECUTOR already set !"))
 }
@@ -87,6 +89,7 @@ struct BcaExecutor {
     dbs_reader: DbsReader,
     self_keypair: Ed25519KeyPair,
     software_version: &'static str,
+    txs_mempool: duniter_mempools::TxsMempool,
 }
 use uninit::extension_traits::VecCapacity;
 impl BcaExecutor {
@@ -265,6 +268,7 @@ mod tests {
                 Seed32::random().expect("fail to gen random seed"),
             ),
             software_version: "test",
+            txs_mempool: duniter_mempools::TxsMempool::new(10),
         })
     }
 
diff --git a/rust-libs/modules/gva/bca/types/Cargo.toml b/rust-libs/modules/gva/bca/types/Cargo.toml
index 69634c022..18bbf84e9 100644
--- a/rust-libs/modules/gva/bca/types/Cargo.toml
+++ b/rust-libs/modules/gva/bca/types/Cargo.toml
@@ -9,6 +9,7 @@ edition = "2018"
 bincode = "1.3"
 dubp = { version = "0.49.0" }
 serde = { version = "1.0.105", features = ["derive"] }
+smallvec = { version = "1.4.0", features = ["serde"] }
 thiserror = "1.0.20"
 
 [features]
diff --git a/rust-libs/modules/gva/bca/types/src/lib.rs b/rust-libs/modules/gva/bca/types/src/lib.rs
index 7e7152085..0f3a78a33 100644
--- a/rust-libs/modules/gva/bca/types/src/lib.rs
+++ b/rust-libs/modules/gva/bca/types/src/lib.rs
@@ -23,6 +23,7 @@
 )]
 
 pub mod prepare_payment;
+pub mod rejected_tx;
 
 use crate::prepare_payment::{PrepareSimplePayment, PrepareSimplePaymentResp};
 
@@ -31,6 +32,7 @@ use dubp::crypto::hashs::Hash;
 use dubp::crypto::keys::ed25519::{PublicKey, Signature};
 use dubp::wallet::prelude::*;
 use serde::{Deserialize, Serialize};
+use smallvec::SmallVec;
 use thiserror::Error;
 
 pub fn bincode_opts() -> impl bincode::Options {
@@ -39,26 +41,36 @@ pub fn bincode_opts() -> impl bincode::Options {
         .allow_trailing_bytes()
 }
 
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)]
+// Request
+
+#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
 pub enum BcaReq {
     V0(BcaReqV0),
     _V1,
 }
 
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)]
+#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
 pub struct BcaReqV0 {
     pub req_id: usize,
     pub req_type: BcaReqTypeV0,
 }
 
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)]
+#[allow(clippy::large_enum_variant)]
+#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
 pub enum BcaReqTypeV0 {
     MembersCount,
     PrepareSimplePayment(PrepareSimplePayment),
     ProofServerPubkey { challenge: [u8; 16] },
     Ping,
+    SendTxs(Txs),
 }
 
+// Request types helpers
+
+pub type Txs = SmallVec<[dubp::documents::transaction::TransactionDocumentV10; 1]>;
+
+// Response
+
 #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
 pub enum BcaResp {
     V0(BcaRespV0),
@@ -82,8 +94,11 @@ pub enum BcaRespTypeV0 {
     MembersCount(u64),
     PrepareSimplePayment(PrepareSimplePaymentResp),
     Pong,
+    RejectedTxs(Vec<rejected_tx::RejectedTx>),
 }
 
+// Result and error
+
 pub type BcaResult = Result<BcaResp, BcaReqExecError>;
 
 #[derive(Clone, Debug, Deserialize, Error, PartialEq, Eq, Serialize)]
diff --git a/rust-libs/modules/gva/bca/types/src/rejected_tx.rs b/rust-libs/modules/gva/bca/types/src/rejected_tx.rs
new file mode 100644
index 000000000..14b06e52b
--- /dev/null
+++ b/rust-libs/modules/gva/bca/types/src/rejected_tx.rs
@@ -0,0 +1,30 @@
+//  Copyright (C) 2020 Éloïs SANCHEZ.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+use crate::*;
+
+#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
+pub struct RejectedTx {
+    pub tx_index: u16,
+    pub reason: RejectedTxReason,
+}
+
+#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
+pub enum RejectedTxReason {
+    DbError(String),
+    InvalidTx(String),
+    MempoolFull,
+    TxAlreadyWritten,
+}
diff --git a/rust-libs/modules/gva/src/lib.rs b/rust-libs/modules/gva/src/lib.rs
index fdda6a321..277783e8f 100644
--- a/rust-libs/modules/gva/src/lib.rs
+++ b/rust-libs/modules/gva/src/lib.rs
@@ -245,6 +245,7 @@ impl GvaModule {
             duniter_gva_dbs_reader::create_dbs_reader(gva_db_ro),
             self_keypair,
             software_version,
+            mempools.txs,
         );
         let gva_schema = duniter_gva_gql::build_schema_with_data(
             duniter_gva_gql::GvaSchemaData {
-- 
GitLab