|
@@ -1,5 +1,5 @@
|
|
//! SQLite storage layer for Verax
|
|
//! SQLite storage layer for Verax
|
|
-use super::{Cursor, ReceivedPaymentStatus};
|
|
|
|
|
|
+use super::{AccountTransactionType, Cursor, ReceivedPaymentStatus};
|
|
use crate::{
|
|
use crate::{
|
|
amount::AmountCents,
|
|
amount::AmountCents,
|
|
storage::{Error, Storage},
|
|
storage::{Error, Storage},
|
|
@@ -30,7 +30,7 @@ async fn find_candidates<'e, 'c: 'e, E>(
|
|
executor: E,
|
|
executor: E,
|
|
cursor: &mut Cursor,
|
|
cursor: &mut Cursor,
|
|
limit: usize,
|
|
limit: usize,
|
|
-) -> Result<Vec<(BaseTx, Revision)>, Error>
|
|
|
|
|
|
+) -> Result<Vec<(BaseTx, Revision, RevId)>, Error>
|
|
where
|
|
where
|
|
E: sqlx::Executor<'c, Database = sqlx::Sqlite>,
|
|
E: sqlx::Executor<'c, Database = sqlx::Sqlite>,
|
|
{
|
|
{
|
|
@@ -51,7 +51,8 @@ where
|
|
r#"
|
|
r#"
|
|
SELECT
|
|
SELECT
|
|
"bt"."blob",
|
|
"bt"."blob",
|
|
- "b"."blob"
|
|
|
|
|
|
+ "b"."blob",
|
|
|
|
+ "t"."revision_id"
|
|
FROM
|
|
FROM
|
|
"transactions" as "t",
|
|
"transactions" as "t",
|
|
"base_transactions" as "bt",
|
|
"base_transactions" as "bt",
|
|
@@ -85,7 +86,8 @@ where
|
|
r#"
|
|
r#"
|
|
SELECT
|
|
SELECT
|
|
"bt"."blob",
|
|
"bt"."blob",
|
|
- "b"."blob"
|
|
|
|
|
|
+ "b"."blob",
|
|
|
|
+ "b"."revision_id"
|
|
FROM
|
|
FROM
|
|
"base_transactions" as "bt",
|
|
"base_transactions" as "bt",
|
|
"revisions" as "b"
|
|
"revisions" as "b"
|
|
@@ -108,12 +110,13 @@ where
|
|
}
|
|
}
|
|
query.fetch_all(executor).await
|
|
query.fetch_all(executor).await
|
|
}
|
|
}
|
|
- PrimaryFilter::Account(account_ids) => {
|
|
|
|
|
|
+ PrimaryFilter::Receives(account_ids) => {
|
|
let sql = format!(
|
|
let sql = format!(
|
|
r#"
|
|
r#"
|
|
SELECT
|
|
SELECT
|
|
"bt"."blob",
|
|
"bt"."blob",
|
|
- "b"."blob"
|
|
|
|
|
|
+ "b"."blob",
|
|
|
|
+ "b"."revision_id"
|
|
FROM
|
|
FROM
|
|
"transaction_accounts" as "ta",
|
|
"transaction_accounts" as "ta",
|
|
"transactions" as "t",
|
|
"transactions" as "t",
|
|
@@ -121,6 +124,7 @@ where
|
|
"revisions" as "b"
|
|
"revisions" as "b"
|
|
WHERE
|
|
WHERE
|
|
"ta"."account_id" IN ({})
|
|
"ta"."account_id" IN ({})
|
|
|
|
+ AND "ta"."relationship" = "{}"
|
|
AND "t"."transaction_id" = "ta"."transaction_id"
|
|
AND "t"."transaction_id" = "ta"."transaction_id"
|
|
AND "t"."revision_id" = "b"."revision_id"
|
|
AND "t"."revision_id" = "b"."revision_id"
|
|
AND "t"."transaction_id" = "bt"."transaction_id"
|
|
AND "t"."transaction_id" = "bt"."transaction_id"
|
|
@@ -129,6 +133,42 @@ where
|
|
LIMIT {} OFFSET {}
|
|
LIMIT {} OFFSET {}
|
|
"#,
|
|
"#,
|
|
"?,".repeat(account_ids.len()).trim_end_matches(","),
|
|
"?,".repeat(account_ids.len()).trim_end_matches(","),
|
|
|
|
+ AccountTransactionType::Receives.to_string(),
|
|
|
|
+ since,
|
|
|
|
+ until,
|
|
|
|
+ limit,
|
|
|
|
+ cursor.filter.skip
|
|
|
|
+ );
|
|
|
|
+ let mut query = sqlx::query(&sql);
|
|
|
|
+ for id in account_ids.iter() {
|
|
|
|
+ query = query.bind(id.to_string());
|
|
|
|
+ }
|
|
|
|
+ query.fetch_all(executor).await
|
|
|
|
+ }
|
|
|
|
+ PrimaryFilter::Spends(account_ids) => {
|
|
|
|
+ let sql = format!(
|
|
|
|
+ r#"
|
|
|
|
+ SELECT
|
|
|
|
+ "bt"."blob",
|
|
|
|
+ "b"."blob",
|
|
|
|
+ "b"."revision_id"
|
|
|
|
+ FROM
|
|
|
|
+ "transaction_accounts" as "ta",
|
|
|
|
+ "transactions" as "t",
|
|
|
|
+ "base_transactions" as "bt",
|
|
|
|
+ "revisions" as "b"
|
|
|
|
+ WHERE
|
|
|
|
+ "ta"."account_id" IN ({})
|
|
|
|
+ AND "ta"."relationship" = "{}"
|
|
|
|
+ AND "t"."transaction_id" = "ta"."transaction_id"
|
|
|
|
+ AND "t"."revision_id" = "b"."revision_id"
|
|
|
|
+ AND "t"."transaction_id" = "bt"."transaction_id"
|
|
|
|
+ {} {}
|
|
|
|
+ ORDER BY "ta"."created_at" DESC
|
|
|
|
+ LIMIT {} OFFSET {}
|
|
|
|
+ "#,
|
|
|
|
+ "?,".repeat(account_ids.len()).trim_end_matches(","),
|
|
|
|
+ AccountTransactionType::Spends.to_string(),
|
|
since,
|
|
since,
|
|
until,
|
|
until,
|
|
limit,
|
|
limit,
|
|
@@ -145,7 +185,8 @@ where
|
|
r#"
|
|
r#"
|
|
SELECT
|
|
SELECT
|
|
"bt"."blob",
|
|
"bt"."blob",
|
|
- "b"."blob"
|
|
|
|
|
|
+ "b"."blob",
|
|
|
|
+ "b"."revision_id"
|
|
FROM
|
|
FROM
|
|
"transactions" as "t",
|
|
"transactions" as "t",
|
|
"base_transactions" as "bt",
|
|
"base_transactions" as "bt",
|
|
@@ -175,7 +216,8 @@ where
|
|
r#"
|
|
r#"
|
|
SELECT
|
|
SELECT
|
|
"bt"."blob",
|
|
"bt"."blob",
|
|
- "b"."blob"
|
|
|
|
|
|
+ "b"."blob",
|
|
|
|
+ "b"."revision_id"
|
|
FROM
|
|
FROM
|
|
"transactions" as "t",
|
|
"transactions" as "t",
|
|
"base_transactions" as "bt",
|
|
"base_transactions" as "bt",
|
|
@@ -206,7 +248,8 @@ where
|
|
r#"
|
|
r#"
|
|
SELECT
|
|
SELECT
|
|
"bt"."blob",
|
|
"bt"."blob",
|
|
- "b"."blob"
|
|
|
|
|
|
+ "b"."blob",
|
|
|
|
+ "b"."revision_id"
|
|
FROM
|
|
FROM
|
|
"transactions" as "t",
|
|
"transactions" as "t",
|
|
"base_transactions" as "bt",
|
|
"base_transactions" as "bt",
|
|
@@ -236,7 +279,8 @@ where
|
|
r#"
|
|
r#"
|
|
SELECT
|
|
SELECT
|
|
"bt"."blob",
|
|
"bt"."blob",
|
|
- "b"."blob"
|
|
|
|
|
|
+ "b"."blob",
|
|
|
|
+ "b"."revision_id"
|
|
FROM
|
|
FROM
|
|
"transactions" as "t",
|
|
"transactions" as "t",
|
|
"base_transactions" as "bt",
|
|
"base_transactions" as "bt",
|
|
@@ -266,9 +310,16 @@ where
|
|
.try_get::<Vec<u8>, usize>(1)
|
|
.try_get::<Vec<u8>, usize>(1)
|
|
.map_err(|e| Error::Storage(e.to_string()))?;
|
|
.map_err(|e| Error::Storage(e.to_string()))?;
|
|
|
|
|
|
|
|
+ let revision_id = RevId::from_str(
|
|
|
|
+ &row.try_get::<String, usize>(2)
|
|
|
|
+ .map_err(|e| Error::Storage(e.to_string()))?,
|
|
|
|
+ )
|
|
|
|
+ .map_err(|e| Error::Storage(e.to_string()))?;
|
|
|
|
+
|
|
Ok((
|
|
Ok((
|
|
from_slice::<BaseTx>(&base_tx)?,
|
|
from_slice::<BaseTx>(&base_tx)?,
|
|
from_slice::<Revision>(&revision)?,
|
|
from_slice::<Revision>(&revision)?,
|
|
|
|
+ revision_id,
|
|
))
|
|
))
|
|
})
|
|
})
|
|
.collect::<Result<Vec<_>, Error>>()?;
|
|
.collect::<Result<Vec<_>, Error>>()?;
|
|
@@ -340,13 +391,14 @@ impl SQLite {
|
|
CREATE INDEX IF NOT EXISTS "spent_by" ON "payments" ("to", "status", "spent_by", "is_negative");
|
|
CREATE INDEX IF NOT EXISTS "spent_by" ON "payments" ("to", "status", "spent_by", "is_negative");
|
|
CREATE TABLE IF NOT EXISTS "transaction_accounts" (
|
|
CREATE TABLE IF NOT EXISTS "transaction_accounts" (
|
|
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
|
+ "relationship" VARCHAR(6) NOT NULL,
|
|
"account_id" VARCHAR(64) NOT NULL,
|
|
"account_id" VARCHAR(64) NOT NULL,
|
|
"transaction_id" VARCHAR(66) NOT NULL,
|
|
"transaction_id" VARCHAR(66) NOT NULL,
|
|
"type" INTEGER NOT NULL,
|
|
"type" INTEGER NOT NULL,
|
|
"created_at" DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
"created_at" DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
"updated_at" DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
"updated_at" DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
);
|
|
- CREATE UNIQUE INDEX IF NOT EXISTS "unique_account_transaction" ON "transaction_accounts" ("account_id", "transaction_id");
|
|
|
|
|
|
+ CREATE UNIQUE INDEX IF NOT EXISTS "unique_account_transaction" ON "transaction_accounts" ("account_id", "transaction_id", "relationship");
|
|
CREATE INDEX IF NOT EXISTS "sorted_account_transaction" ON "transaction_accounts" ("account_id", "id" desc);
|
|
CREATE INDEX IF NOT EXISTS "sorted_account_transaction" ON "transaction_accounts" ("account_id", "id" desc);
|
|
"#,
|
|
"#,
|
|
)
|
|
)
|
|
@@ -615,7 +667,8 @@ impl Storage for SQLite {
|
|
|
|
|
|
let mut iteration_result = candidates
|
|
let mut iteration_result = candidates
|
|
.into_iter()
|
|
.into_iter()
|
|
- .filter(|(base, revision)| cursor.matches(base, revision))
|
|
|
|
|
|
+ .filter(|(base, revision, revision_id)| cursor.matches(base, revision, revision_id))
|
|
|
|
+ .map(|(base, revision, _)| (base, revision))
|
|
.collect::<Vec<_>>();
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
results.append(&mut iteration_result);
|
|
results.append(&mut iteration_result);
|