commit 5ac32c8b645d52c59f9be7ef29332aa228d26645
parent ee9b262ffeafe5f5af78d5382e5033b386d78f1d
Author: Antoine A <>
Date: Mon, 30 Oct 2023 14:06:44 +0000
Fix bank install, remove unused dependencies and clean schema
Diffstat:
7 files changed, 29 insertions(+), 207 deletions(-)
diff --git a/Makefile b/Makefile
@@ -45,7 +45,9 @@ install-bank:
install -D database-versioning/versioning.sql -t $(bank_sql_dir)
install -d $(spa_dir)
cp contrib/wallet-core/demobank/* $(spa_dir)/
- ./gradlew -q -Pprefix=$(abs_destdir)$(prefix) bank:installToPrefix
+ ./gradlew bank:installShadowDist
+ install -d $(abs_destdir)$(prefix)
+ cp -r bank/build/install/bank-shadow/* -d $(abs_destdir)$(prefix)
install-nexus:
install -d $(nexus_config_dir)
diff --git a/bank/build.gradle b/bank/build.gradle
@@ -8,8 +8,8 @@ plugins {
}
java {
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
}
version = rootProject.version
@@ -26,38 +26,16 @@ compileTestKotlin {
}
}
-tasks.register('installToPrefix', Copy) {
- dependsOn(installShadowDist)
- from("build/install/bank-shadow") {
- include("**/libeufin-bank")
- include("**/*.jar")
- }
- /**
- * Reads from command line -Pkey=value options,
- * with a default (/tmp) if the key is not found.
- *
- * project.findProperty('prefix') ?: '/tmp'
- */
- into "${project.findProperty('prefix') ?: '/tmp'}"
-}
-// apply plugin: 'kotlinx-serialization'
-
sourceSets {
main.java.srcDirs = ['src/main/kotlin']
}
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
- implementation 'ch.qos.logback:logback-classic:1.4.5'
implementation project(":util")
- // XML:
- implementation "javax.xml.bind:jaxb-api:2.3.0"
- implementation "org.glassfish.jaxb:jaxb-runtime:2.3.1"
-
implementation 'org.postgresql:postgresql:42.6.0'
implementation 'com.zaxxer:HikariCP:5.0.1'
- implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.21'
implementation "com.github.ajalt.clikt:clikt:4.2.1"
implementation "io.ktor:ktor-server-core:$ktor_version"
diff --git a/bank/src/test/kotlin/AmountTest.kt b/bank/src/test/kotlin/AmountTest.kt
@@ -206,7 +206,7 @@ class AmountTest {
@Test
fun mul() = dbSetup { db ->
db.conn { conn ->
- val stmt = conn.prepareStatement("SELECT product.val, product.frac FROM amount_mul((?, ?)::taler_amount, (?, ?)::taler_amount) as product")
+ val stmt = conn.prepareStatement("SELECT product.val, product.frac FROM amount_mul((?, ?)::taler_amount, (?, ?)::taler_amount, NULL) as product")
operator fun TalerAmount.times(increment: TalerAmount): TalerAmount? {
stmt.setLong(1, value)
stmt.setInt(2, frac)
@@ -221,9 +221,10 @@ class AmountTest {
}!!
}
+
assertEquals(TalerAmount("EUR:6.41") * TalerAmount("EUR:4.69"), TalerAmount("EUR:30.0629"))
assertEquals(TalerAmount("EUR:6.41") * TalerAmount("EUR:1.000001"), TalerAmount("EUR:6.41000641"))
- assertEquals(TalerAmount("EUR:0.99999999") * TalerAmount("EUR:2.5"), TalerAmount("EUR:2.49999998"))
+ assertEquals(TalerAmount("EUR:0.99999999") * TalerAmount("EUR:2.5"), TalerAmount("EUR:2.49999997"))
assertEquals(TalerAmount("EUR:${TalerAmount.MAX_VALUE}.99999999") * TalerAmount("EUR:1"), TalerAmount("EUR:${TalerAmount.MAX_VALUE}.99999999"))
assertEquals(TalerAmount("EUR:${TalerAmount.MAX_VALUE/4}") * TalerAmount("EUR:4"), TalerAmount("EUR:${TalerAmount.MAX_VALUE}"))
assertException("ERROR: amount value overflowed") { TalerAmount(TalerAmount.MAX_VALUE/3, 0, "EUR") * TalerAmount(3, 1, "EUR") }
diff --git a/contrib/docker-launcher/libeufin-bank.conf b/contrib/docker-launcher/libeufin-bank.conf
@@ -11,15 +11,4 @@ PORT = 8080
[libeufin-bankdb-postgres]
SQL_DIR = /usr/local/share/taler/sql/libeufin-bank/
-CONFIG = postgresql:///libeufinbank
-
-[currency-kudos]
-ENABLED = YES
-name = "Kudos (Taler Demonstrator)"
-code = "KUDOS"
-decimal_separator = ","
-fractional_input_digits = 2
-fractional_normal_digits = 2
-fractional_trailing_zero_digits = 2
-is_currency_name_leading = NO
-alt_unit_names = {"0":"ク"}
-\ No newline at end of file
+CONFIG = postgresql:///libeufinbank
+\ No newline at end of file
diff --git a/contrib/libeufin-bank.conf b/contrib/libeufin-bank.conf
@@ -39,15 +39,4 @@ PORT = 8080
SQL_DIR = $DATADIR/sql/
# DB connection string
-CONFIG = postgresql:///libeufinbank
-
-[currency-kudos]
-ENABLED = YES
-name = "Kudos (Taler Demonstrator)"
-code = "KUDOS"
-decimal_separator = ","
-fractional_input_digits = 2
-fractional_normal_digits = 2
-fractional_trailing_zero_digits = 2
-is_currency_name_leading = NO
-alt_unit_names = {"0":"ク"}
-\ No newline at end of file
+CONFIG = postgresql:///libeufinbank
+\ No newline at end of file
diff --git a/database-versioning/libeufin-bank-0001.sql b/database-versioning/libeufin-bank-0001.sql
@@ -50,6 +50,10 @@ CREATE TYPE subscriber_state_enum
CREATE TYPE stat_timeframe_enum
AS ENUM ('hour', 'day', 'month', 'year');
+CREATE TYPE rounding_mode
+ AS ENUM ('nearest', 'up', 'down'); -- up is toward infinity and down toward zero
+
+
-- FIXME: comments on types (see exchange for example)!
-- start of: bank accounts
@@ -182,151 +186,6 @@ COMMENT ON COLUMN cashout_operations.tan_code
-- end of: cashout management
--- start of: EBICS management
-
-CREATE TABLE IF NOT EXISTS ebics_hosts
- (ebics_host_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
- ,ebics_host_name TEXT NOT NULL
- ,ebics_version TEXT NOT NULL -- FIXME: This should be an enum
- -- FIXME: Do we want to specify the dialect here?
- ,encryption_private_key BYTEA NOT NULL
- ,signature_private_key BYTEA NOT NULL
- );
-
-CREATE TABLE IF NOT EXISTS ebics_subscribers
- (ebics_subscriber_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
- ,ebics_user_id TEXT NOT NULL
- ,ebics_partner_id TEXT NOT NULL
- ,ebics_system_id TEXT
- ,ebics_host_id BIGINT NOT NULL REFERENCES ebics_hosts(ebics_host_id)
- ,signature_key_rsa_pub BYTEA NOT NULL
- ,signature_key_state subscriber_key_state_enum NOT NULL
- ,encryption_key_rsa_pub BYTEA NOT NULL
- ,encryption_key_state subscriber_key_state_enum NOT NULL
- ,subscriber_state subscriber_state_enum DEFAULT 'new' NOT NULL
- -- FIXME: Do we need some information about the next order ID? There is a bug open.
- );
-COMMENT ON COLUMN ebics_subscribers.subscriber_state
- IS 'Tracks the state changes of one subscriber.'; -- Really needed?
-
--- FIXME: comment this table
--- FIXME: indices on both columns individually
-CREATE TABLE IF NOT EXISTS ebics_subscribers_of_bank_accounts
- (ebics_subscriber_id BIGINT NOT NULL
- REFERENCES ebics_subscribers(ebics_subscriber_id)
- ,bank_account_id BIGINT NOT NULL
- REFERENCES bank_accounts(bank_account_id)
- );
-
-
-CREATE TABLE IF NOT EXISTS ebics_download_transactions
- (transaction_id TEXT PRIMARY KEY
- ,order_type VARCHAR(3) NOT NULL
- -- EBICS3: ,btf_type TEXT -- fixme: document: in EBICS 2.x this can be NULL
- -- FIXME: see what else we need for EBICS 3
- ,ebics_host_id BIGINT NOT NULL
- REFERENCES ebics_hosts(ebics_host_id)
- ON DELETE CASCADE
- ON UPDATE RESTRICT
- ,ebics_subscriber BIGINT NOT NULL
- REFERENCES ebics_subscribers(ebics_subscriber_id)
- ON DELETE CASCADE
- ON UPDATE RESTRICT
- ,encoded_response TEXT NOT NULL
- ,transaction_key_enc BYTEA NOT NULL
- ,num_segments INT NOT NULL
- ,segment_size INT NOT NULL
- ,receipt_received BOOLEAN NOT NULL DEFAULT (FALSE) -- FIXME: Do we need this field if we anyway delete the entry after the receipt?
- -- FIXME: Download start time for garbage collection / timeouts
- );
-
-COMMENT ON TABLE ebics_download_transactions
- IS 'Tracks the evolution of one EBICS download transaction';
-COMMENT ON COLUMN ebics_download_transactions.ebics_host_id
- IS 'EBICS host that governs this transaction'; -- exists for a multi-host scenario.
-
-CREATE TABLE IF NOT EXISTS ebics_upload_transactions
- (ebics_transaction_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
- ,order_type VARCHAR(3) NOT NULL
- -- EBICS3: ,btf_type TEXT -- fixme: document: in EBICS 2.x this can be NULL
- -- FIXME: see what else we need for EBICS 3
- ,order_id TEXT NOT NULL
- ,ebics_host BIGINT NOT NULL
- REFERENCES ebics_hosts(ebics_host_id)
- ON DELETE RESTRICT
- ON UPDATE RESTRICT
- ,ebics_subscriber BIGINT NOT NULL
- REFERENCES ebics_subscribers(ebics_subscriber_id)
- ON DELETE RESTRICT
- ON UPDATE RESTRICT
- ,num_segments INT NOT NULL
- ,last_seen_segment INT NOT NULL
- ,transaction_key_enc BYTEA NOT NULL
- -- FIXME: Download start time for garbage collection / timeouts
- );
-
-CREATE TABLE IF NOT EXISTS ebics_upload_transaction_chunks
- (ebics_transaction_id BIGINT
- REFERENCES ebics_upload_transactions(ebics_transaction_id)
- ON DELETE CASCADE
- ON UPDATE RESTRICT
- ,upload_chunk_index INT NOT NULL
- ,upload_chunk_content BYTEA NOT NULL
- );
-
--- FIXME: look at the code how it's used
--- I *think* this is only used for upload orders.
--- I am not sure if the signature (especially with VEU)
--- can be uploaded before the order itself has been uploaded
-CREATE TABLE IF NOT EXISTS ebics_order_signatures
- (order_signature_id SERIAL PRIMARY KEY
- ,ebics_transaction_id BIGINT
- REFERENCES ebics_upload_transactions(ebics_transaction_id)
- ON DELETE CASCADE
- ON UPDATE RESTRICT
- ,ebics_subscriber_id BIGINT
- REFERENCES ebics_subscribers(ebics_subscriber_id)
- ON DELETE CASCADE
- ON UPDATE RESTRICT
- -- FIXME: do we also need to reference the ebics host? or does the subscriber uniquely determine it?
- ,order_id TEXT NOT NULL
- ,order_type TEXT NOT NULL
- ,signature_algorithm TEXT NOT NULL
- ,signature_value BYTEA NOT NULL
- );
-
-COMMENT ON TABLE ebics_order_signatures
- IS 'Keeps signature data collected from the subscribers.';
-
--- end of: EBICS management
-
--- start of: accounts activity report
-
--- Really keep this table? It tracks the EBICS reports.
-CREATE TABLE IF NOT EXISTS bank_account_reports
- (report_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
- ,creation_time BIGINT NOT NULL
- ,xml_message TEXT NOT NULL
- ,bank_account BIGINT NOT NULL
- REFERENCES bank_accounts(bank_account_id)
- ON DELETE CASCADE
- ON UPDATE RESTRICT
- );
-
--- Really keep this table? It tracks the EBICS statements
--- mostly because they are supposed never to change. Not used
-CREATE TABLE IF NOT EXISTS bank_account_statements
- (statement_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE
- ,creation_time BIGINT NOT NULL
- ,xml_message TEXT NOT NULL
- ,bank_account BIGINT NOT NULL
- REFERENCES bank_accounts(bank_account_id)
- ON DELETE CASCADE
- ON UPDATE RESTRICT
- ,balance_clbd TEXT NOT NULL -- FIXME: name. balance_closing?
- );
--- end of: accounts activity report
-
-- start of: Taler integration
CREATE TABLE IF NOT EXISTS taler_exchange_outgoing
(exchange_outgoing_id BIGINT GENERATED BY DEFAULT AS IDENTITY
diff --git a/database-versioning/libeufin-bank-procedures.sql b/database-versioning/libeufin-bank-procedures.sql
@@ -34,20 +34,22 @@ COMMENT ON FUNCTION amount_add
CREATE OR REPLACE FUNCTION amount_mul(
IN a taler_amount
,IN b taler_amount
+ ,IN rounding rounding_mode
,OUT product taler_amount
)
LANGUAGE plpgsql AS $$
DECLARE
- tmp NUMERIC(24, 8); -- 16 digit for val and 8 for frac
+ tmp NUMERIC(25, 9); -- 16 digit for val, 8 for frac and 1 for rounding error
+ rounding_error INT2;
BEGIN
- -- TODO write custom multiplication logic to get more control over rounding
- tmp = (a.val::numeric(24, 8) + a.frac::numeric(24, 8) / 100000000) * (b.val::numeric(24, 8) + b.frac::numeric(24, 8) / 100000000);
- product = (trunc(tmp)::int8, (tmp * 100000000 % 100000000)::int4);
- IF (product.val > 1::bigint<<52) THEN
- RAISE EXCEPTION 'amount value overflowed';
- END IF;
+ tmp = (a.val::numeric(25, 9) + a.frac::numeric(25, 9) / 100000000) * (b.val::numeric(25, 9) + b.frac::numeric(25, 9) / 100000000);
+ product = (trunc(tmp)::int8, (tmp * 1000000000 % 1000000000)::int4);
+ rounding_error = product.frac % 10;
+ product.frac = product.frac / 10;
+ -- TODO handle rounding
+ SELECT normalized.val, normalized.frac INTO product.val, product.frac FROM amount_normalize(product) as normalized;
END $$;
-COMMENT ON FUNCTION amount_mul -- TODO document rounding
+COMMENT ON FUNCTION amount_mul
IS 'Returns the product of two amounts. It raises an exception when the resulting .val is larger than 2^52';
CREATE OR REPLACE FUNCTION amount_left_minus_right(
@@ -1271,12 +1273,14 @@ LANGUAGE plpgsql AS $$
DECLARE
sell_at_ratio taler_amount;
sell_out_fee taler_amount;
+ rounding_mode rounding_mode;
calculation_ok BOOLEAN;
BEGIN
SELECT value['val']::int8, value['frac']::int4 INTO sell_at_ratio.val, sell_at_ratio.frac FROM config WHERE key='sell_at_ratio';
SELECT value['val']::int8, value['frac']::int4 INTO sell_out_fee.val, sell_out_fee.frac FROM config WHERE key='sell_out_fee';
+ rounding_mode = 'nearest'; -- TODO rounding error config
- SELECT product.val, product.frac INTO fiat_amount.val, fiat_amount.frac FROM amount_mul(internal_amount, sell_at_ratio) as product;
+ SELECT product.val, product.frac INTO fiat_amount.val, fiat_amount.frac FROM amount_mul(internal_amount, sell_at_ratio, rounding_mode) as product;
SELECT (diff).val, (diff).frac, ok INTO fiat_amount.val, fiat_amount.frac, calculation_ok FROM amount_left_minus_right(fiat_amount, sell_out_fee);
IF NOT calculation_ok THEN