From 015481cee19c5efc684f488074cc0de878ba976c Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sun, 25 Jan 2026 17:36:24 +0100 Subject: [PATCH] implement compact confirmed transaction struct in C --- dlt-connector/.gitignore | 2 + dlt-connector/bun-zigar.toml | 8 ++ dlt-connector/bun.lock | 11 +- dlt-connector/bunfig.toml | 1 + dlt-connector/c/grdc/grdc_account_balance.h | 23 ++++ dlt-connector/c/grdc/grdc_confirmed_tx.h | 104 +++++++++++++++ dlt-connector/c/grdc/grdc_public_key_index.h | 21 +++ dlt-connector/c/grdc/grdc_tx_id.h | 25 ++++ dlt-connector/c/grdc/grdc_tx_timestamps.h | 42 ++++++ dlt-connector/c/grdd/grdd_address_type.h | 23 ++++ .../c/grdd/grdd_balance_derivation_type.h | 26 ++++ dlt-connector/c/grdd/grdd_cross_group_type.h | 20 +++ dlt-connector/c/grdd/grdd_timestamp.h | 38 ++++++ dlt-connector/c/grdd/grdd_transaction_type.h | 56 ++++++++ dlt-connector/c/grdl/grdl_unit.c | 123 ++++++++++++++++++ dlt-connector/c/grdl/grdl_unit.h | 84 ++++++++++++ dlt-connector/package.json | 1 + dlt-connector/zig/hello.zig | 5 + 18 files changed, 612 insertions(+), 1 deletion(-) create mode 100644 dlt-connector/bun-zigar.toml create mode 100644 dlt-connector/bunfig.toml create mode 100644 dlt-connector/c/grdc/grdc_account_balance.h create mode 100644 dlt-connector/c/grdc/grdc_confirmed_tx.h create mode 100644 dlt-connector/c/grdc/grdc_public_key_index.h create mode 100644 dlt-connector/c/grdc/grdc_tx_id.h create mode 100644 dlt-connector/c/grdc/grdc_tx_timestamps.h create mode 100644 dlt-connector/c/grdd/grdd_address_type.h create mode 100644 dlt-connector/c/grdd/grdd_balance_derivation_type.h create mode 100644 dlt-connector/c/grdd/grdd_cross_group_type.h create mode 100644 dlt-connector/c/grdd/grdd_timestamp.h create mode 100644 dlt-connector/c/grdd/grdd_transaction_type.h create mode 100644 dlt-connector/c/grdl/grdl_unit.c create mode 100644 dlt-connector/c/grdl/grdl_unit.h create mode 100644 dlt-connector/zig/hello.zig diff --git a/dlt-connector/.gitignore b/dlt-connector/.gitignore index 4c6422640..c1c4be080 100644 --- a/dlt-connector/.gitignore +++ b/dlt-connector/.gitignore @@ -3,6 +3,8 @@ /.env.bak /build/ /locales/ +lib +.zigar-cache package-json.lock coverage # emacs diff --git a/dlt-connector/bun-zigar.toml b/dlt-connector/bun-zigar.toml new file mode 100644 index 000000000..5a2dc3f56 --- /dev/null +++ b/dlt-connector/bun-zigar.toml @@ -0,0 +1,8 @@ +optimize = "ReleaseSmall" + +[modules."lib/hello.zigar"] +source = "zig/hello.zig" + +[[targets]] +arch = "x64" +platform = "linux" diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index faaacaeb4..1bbaedc8c 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -5,6 +5,7 @@ "": { "name": "dlt-connector", "dependencies": { + "bun-zigar": "^0.15.2", "cross-env": "^7.0.3", "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#f265dbb1780a912cf8b0418dfe3eaf5cdc5b51cf", }, @@ -392,6 +393,8 @@ "bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="], + "bun-zigar": ["bun-zigar@0.15.2", "", { "dependencies": { "node-zigar-addon": "0.15.2", "zigar-compiler": "^0.15.2" }, "bin": { "zigar": "bin/cli.js", "bun-zigar": "bin/cli.js" } }, "sha512-slEHTEapQEIqB86OeiToPuuFXe39DCIYISTPzbIMBTZL34vRzCIa5wFn5ATudauHFFwl5/y5JYv8tluk2QL9Eg=="], + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], @@ -784,7 +787,7 @@ "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], - "node-api-headers": ["node-api-headers@1.6.0", "", {}, "sha512-81T99+mWLZnxX0LlZPYuafyFlxVVaWKQ0BDAbSrOqLO+v+gzCzu0GTAVNeVK8lucqjqo9L/1UcK9cpkem8Py4Q=="], + "node-api-headers": ["node-api-headers@1.8.0", "", {}, "sha512-jfnmiKWjRAGbdD1yQS28bknFM1tbHC1oucyuMPjmkEs+kpiu76aRs40WlTmBmyEgzDM76ge1DQ7XJ3R5deiVjQ=="], "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], @@ -792,6 +795,8 @@ "node-releases": ["node-releases@2.0.26", "", {}, "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA=="], + "node-zigar-addon": ["node-zigar-addon@0.15.2", "", { "dependencies": { "node-api-headers": "^1.7.0" } }, "sha512-QjJcPRtUZLkULaFXapAvTzLKKRddgaupr7wQqgDUQo541FMCXAhgWdZJtNcIgCNykJG0bG0Fza5VTKBdSvyavQ=="], + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], "npm-path": ["npm-path@2.0.4", "", { "dependencies": { "which": "^1.2.10" }, "bin": { "npm-path": "bin/npm-path" } }, "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw=="], @@ -1060,6 +1065,8 @@ "yoctocolors-cjs": ["yoctocolors-cjs@2.1.3", "", {}, "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw=="], + "zigar-compiler": ["zigar-compiler@0.15.2", "", {}, "sha512-zlJ8kUwndwrLl4iRlIWEcidC2rcSsfeWM0jvbSoxUVf+SEKd4bVik3z4YDivuyX3SUiUjpCMNyp65etD6BKRmQ=="], + "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "@babel/core/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], @@ -1104,6 +1111,8 @@ "cmake-js/fs-extra": ["fs-extra@11.3.2", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A=="], + "cmake-js/node-api-headers": ["node-api-headers@1.6.0", "", {}, "sha512-81T99+mWLZnxX0LlZPYuafyFlxVVaWKQ0BDAbSrOqLO+v+gzCzu0GTAVNeVK8lucqjqo9L/1UcK9cpkem8Py4Q=="], + "connect/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "elliptic/bn.js": ["bn.js@4.12.2", "", {}, "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw=="], diff --git a/dlt-connector/bunfig.toml b/dlt-connector/bunfig.toml new file mode 100644 index 000000000..4299d9c62 --- /dev/null +++ b/dlt-connector/bunfig.toml @@ -0,0 +1 @@ +preload = ["bun-zigar"] diff --git a/dlt-connector/c/grdc/grdc_account_balance.h b/dlt-connector/c/grdc/grdc_account_balance.h new file mode 100644 index 000000000..fc38b1926 --- /dev/null +++ b/dlt-connector/c/grdc/grdc_account_balance.h @@ -0,0 +1,23 @@ +#ifndef __GRADIDO_BLOCKCHAIN_C_COMPACT_ACCOUNT_BALANCE_H +#define __GRADIDO_BLOCKCHAIN_C_COMPACT_ACCOUNT_BALANCE_H + +#include +#include "grdc_public_key_index.h" +#include "../grdl/grdl_unit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct grdc_account_balance +{ + grdl_unit balance; + grdc_public_key_index publicKeyIndex; +} grdc_account_balance; + +#ifdef __cplusplus +} +#endif + + +#endif // __GRADIDO_BLOCKCHAIN_C_COMPACT_ACCOUNT_BALANCE_H \ No newline at end of file diff --git a/dlt-connector/c/grdc/grdc_confirmed_tx.h b/dlt-connector/c/grdc/grdc_confirmed_tx.h new file mode 100644 index 000000000..999e4633d --- /dev/null +++ b/dlt-connector/c/grdc/grdc_confirmed_tx.h @@ -0,0 +1,104 @@ +#ifndef __GRADIDO_BLOCKCHAIN_C_COMPACT_CONFIRMED_TRANSACTION_COMPACT_H +#define __GRADIDO_BLOCKCHAIN_C_COMPACT_CONFIRMED_TRANSACTION_COMPACT_H + +#include +#include "grdc_account_balance.h" +#include "grdc_public_key_index.h" +#include "grdc_tx_id.h" +#include "grdc_tx_timestamps.h" +#include "../grdd/grdd_address_type.h" +#include "../grdd/grdd_balance_derivation_type.h" +#include "../grdd/grdd_cross_group_type.h" +#include "../grdd/grdd_transaction_type.h" +#include "../grdl/grdl_unit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Gradido Compact Confirmed Transaction +struct grdc_confirmed_tx +{ + grdc_tx_timestamps timestamps; + + // inline Timestamp getConfirmedAt() const { return timestamps.getConfirmedAt(); } + // inline Timestamp getCreatedAt() const { return timestamps.getCreatedAt(); } + + // txId and pairingTxId packed to save 8 Bytes padding + uint64_t txNrs[2]; + uint32_t communityIdIndex[2]; + // inline TxId getTxId() const { return TxId(txNrs[0], communityIdIndex[0]); } + // for cross group transactions, else empty + // inline TxId getPairingTxId() const { return TxId(txNrs[1], communityIdIndex[1]); } + + // account balances and memos via txId in separate list/manager/thingy + + // enums, usually uint8_t + uint8_t crossGroupType; // grdd_cross_group_type + uint8_t transactionType; // grdd_transaction_type + uint8_t balanceDerivationType; // grdd_balance_derivation_type + uint8_t accountBalanceCount; + + grdc_account_balance accountBalances[2]; + + // common fields for most transactions + union { // 24 Bytes + struct { + grdl_unit amount; // 8 Bytes + grdc_public_key_index recipientPublicKeyIndex; // 8 Bytes + uint64_t targetDate; // 8 Bytes + } creation; + struct { + grdl_unit amount; // 8 Bytes + grdc_public_key_index senderPublicKeyIndex; // 8 Bytes + grdc_public_key_index recipientPublicKeyIndex; // 8 Bytes + } transfer; // also used for redeem deferred transfer, and deferredTransferTransactionNr is stored in extra dictionary + struct { + grdl_unit amount; // 8 Bytes + // work only on local, take communityIdIndex from txId + uint32_t senderPublicKeyIndex; // 4 Bytes + uint32_t recipientPublicKeyIndex; // 4 Bytes + uint32_t timeoutDuration; // 4 Bytes + } deferredTransfer; // fund deferred transfer address only on your own community + struct { + grdc_tx_id deferredTransferTransactionNr; // 16 Bytes, contain 4 Bytes padding + } timeoutDeferredTransfer; + struct { + uint8_t addressType; // grdd_address_type // 1 Byte + uint16_t derivationIndex; // 2 Byte (for the time beeing, update if more than 65535 are needed) + uint32_t nameHashIndex; // 4 Bytes + grdc_public_key_index userPublicKeyIndex; // 8 Bytes + grdc_public_key_index accountPublicKeyIndex; // 8 Bytes + } registerAddress; + struct { + grdc_public_key_index communityPublicKeyIndex; // 8 Bytes + grdc_public_key_index communityAufPublicKeyIndex; // 8 Bytes + grdc_public_key_index communityGmwPublicKeyIndex; // 8 Bytes + } communityRoot; + }; +}; + +inline grdd_timestamp grdc_confirmed_tx_get_confirmed_at(const grdc_confirmed_tx* c) { + return grdc_tx_timestamps_get_confirmed_at(&c->timestamps); +} + +inline grdd_timestamp grdc_confirmed_tx_get_created_at(const grdc_confirmed_tx* c) { + return grdc_tx_timestamps_get_created_at(&c->timestamps); +} + +inline grdc_tx_id grdc_confirmed_tx_get_tx_id(const grdc_confirmed_tx* c) { + grdc_tx_id txId{.nr = c->txNrs[0], .communityIdIndex = c->communityIdIndex[0]}; + return txId; +} + +inline grdc_tx_id grdc_confirmed_tx_get_pairing_tx_id(const grdc_confirmed_tx* c) { + grdc_tx_id pairingTxId{.nr = c->txNrs[1], .communityIdIndex = c->communityIdIndex[1]}; + return pairingTxId; +} + +#ifdef __cplusplus +} +#endif + + +#endif //__GRADIDO_BLOCKCHAIN_C_COMPACT_CONFIRMED_TRANSACTION_COMPACT_H \ No newline at end of file diff --git a/dlt-connector/c/grdc/grdc_public_key_index.h b/dlt-connector/c/grdc/grdc_public_key_index.h new file mode 100644 index 000000000..6ab88fcbf --- /dev/null +++ b/dlt-connector/c/grdc/grdc_public_key_index.h @@ -0,0 +1,21 @@ +#ifndef __GRADIDO_BLOCKCHAIN_C_COMPACT_PUBLIC_KEY_INDEX_H +#define __GRADIDO_BLOCKCHAIN_C_COMPACT_PUBLIC_KEY_INDEX_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct grdc_public_key_index +{ + uint32_t publicKeyIndex; + uint32_t communityIdIndex; +} grdc_public_key_index; + +#ifdef __cplusplus +} +#endif + + +#endif // __GRADIDO_BLOCKCHAIN_C_COMPACT_PUBLIC_KEY_INDEX_H \ No newline at end of file diff --git a/dlt-connector/c/grdc/grdc_tx_id.h b/dlt-connector/c/grdc/grdc_tx_id.h new file mode 100644 index 000000000..b8a1ed12c --- /dev/null +++ b/dlt-connector/c/grdc/grdc_tx_id.h @@ -0,0 +1,25 @@ +#ifndef __GRADIDO_BLOCKCHAIN_C_COMPACT_TRANSACTION_ID +#define __GRADIDO_BLOCKCHAIN_C_COMPACT_TRANSACTION_ID + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct grdc_tx_id +{ + uint64_t nr; + uint32_t communityIdIndex; +} grdc_tx_id; + +inline bool grdc_tx_id_empty(const grdc_tx_id* id) { + return !id->nr && !id->communityIdIndex; +} + +#ifdef __cplusplus +} +#endif + +#endif // __GRADIDO_BLOCKCHAIN_C_COMPACT_TRANSACTION_ID diff --git a/dlt-connector/c/grdc/grdc_tx_timestamps.h b/dlt-connector/c/grdc/grdc_tx_timestamps.h new file mode 100644 index 000000000..ab2e331d6 --- /dev/null +++ b/dlt-connector/c/grdc/grdc_tx_timestamps.h @@ -0,0 +1,42 @@ +#ifndef __GRADIDO_BLOCKCHAIN_C_COMPACT_TRANSACTION_TIMESTAMPS_H +#define __GRADIDO_BLOCKCHAIN_C_COMPACT_TRANSACTION_TIMESTAMPS_H + +#include +#include "../grdd/grdd_timestamp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct grdc_tx_timestamps +{ + uint64_t confirmedSeconds; + uint32_t confirmedNanos; + int32_t deltaMs; // add to confirmed second and nanos to get created_at +} grdc_tx_timestamps; + +inline grdd_timestamp grdc_tx_timestamps_get_confirmed_at(const grdc_tx_timestamps* in) { + grdd_timestamp t; + t.seconds = in->confirmedSeconds; + t.nanos = in->confirmedNanos; + return t; +} + +inline grdd_timestamp grdc_tx_timestamps_get_created_at(const grdc_tx_timestamps* in) { + grdd_timestamp t; + uint64_t sec = (in->confirmedSeconds + in->deltaMs) / 1000; + uint32_t ns = (in->confirmedNanos + (in->deltaMs % 1000)) * 1000000; + if (ns >= 1000000000) { + sec += 1; + ns -= 1000000000; + } + t.seconds = sec; + t.nanos = ns; + return t; +} + +#ifdef __cplusplus +} +#endif + +#endif //__GRADIDO_BLOCKCHAIN_C_COMPACT_TRANSACTION_TIMESTAMPS_H \ No newline at end of file diff --git a/dlt-connector/c/grdd/grdd_address_type.h b/dlt-connector/c/grdd/grdd_address_type.h new file mode 100644 index 000000000..c49593b00 --- /dev/null +++ b/dlt-connector/c/grdd/grdd_address_type.h @@ -0,0 +1,23 @@ +#ifndef __GRADIDO_BLOCKCHAIN_C_DATA_ADDRESS_TYPE_H +#define __GRADIDO_BLOCKCHAIN_C_DATA_ADDRESS_TYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum grdd_address_type { + GRDD_ADDRESS_TYPE_NONE = 0, // if no address was found + GRDD_ADDRESS_TYPE_COMMUNITY_HUMAN = 1, // creation account for human + GRDD_ADDRESS_TYPE_COMMUNITY_GMW = 2, // community public budget account + GRDD_ADDRESS_TYPE_COMMUNITY_AUF = 3, // community compensation and environment founds account + GRDD_ADDRESS_TYPE_COMMUNITY_PROJECT = 4, // no creations allowed + GRDD_ADDRESS_TYPE_SUBACCOUNT = 5, // no creations allowed + GRDD_ADDRESS_TYPE_CRYPTO_ACCOUNT = 6, // user control his keys, no creations + GRDD_ADDRESS_TYPE_DEFERRED_TRANSFER = 7 // special type, no need for register address +}; + +#ifdef __cplusplus +} +#endif + +#endif //__GRADIDO_BLOCKCHAIN_C_DATA_ADDRESS_TYPE_H \ No newline at end of file diff --git a/dlt-connector/c/grdd/grdd_balance_derivation_type.h b/dlt-connector/c/grdd/grdd_balance_derivation_type.h new file mode 100644 index 000000000..1a24131ac --- /dev/null +++ b/dlt-connector/c/grdd/grdd_balance_derivation_type.h @@ -0,0 +1,26 @@ +#ifndef GRADIDO_BLOCKCHAIN_C_DATA_BALANCE_DERIVATION_TYPE_H +#define GRADIDO_BLOCKCHAIN_C_DATA_BALANCE_DERIVATION_TYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @enum grdd_balance_derivation_type + * + * Flag to decide if Node calculates balance and decay + * or trusts external data. + */ +enum grdd_balance_derivation_type { + GRDD_BALANCE_DERIVATION_UNSPECIFIED = 0, + /* Balances & decay can be recalculated deterministically */ + GRDD_BALANCE_DERIVATION_NODE = 1, + /* Balances are accepted as-is from external / legacy system */ + GRDD_BALANCE_DERIVATION_EXTERN = 2 +}; + +#ifdef __cplusplus +} +#endif + +#endif /* GRADIDO_BLOCKCHAIN_C_DATA_BALANCE_DERIVATION_TYPE_H */ diff --git a/dlt-connector/c/grdd/grdd_cross_group_type.h b/dlt-connector/c/grdd/grdd_cross_group_type.h new file mode 100644 index 000000000..2a0c4a72a --- /dev/null +++ b/dlt-connector/c/grdd/grdd_cross_group_type.h @@ -0,0 +1,20 @@ +#ifndef __GRADIDO_BLOCKCHAIN_C_DATA_CROSS_GROUP_TYPE_H +#define __GRADIDO_BLOCKCHAIN_C_DATA_CROSS_GROUP_TYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum grdd_cross_group_type +{ + GRDD_CROSS_GROUP_TYPE_LOCAL = 0, + GRDD_CROSS_GROUP_TYPE_INBOUND = 1, + GRDD_CROSS_GROUP_TYPE_OUTBOUND = 2, + GRDD_CROSS_GROUP_TYPE_CROSS = 3 +}; + +#ifdef __cplusplus +} +#endif + +#endif // __GRADIDO_BLOCKCHAIN_C_DATA_CROSS_GROUP_TYPE_H \ No newline at end of file diff --git a/dlt-connector/c/grdd/grdd_timestamp.h b/dlt-connector/c/grdd/grdd_timestamp.h new file mode 100644 index 000000000..2bf54de67 --- /dev/null +++ b/dlt-connector/c/grdd/grdd_timestamp.h @@ -0,0 +1,38 @@ +#ifndef __GRADIDO_BLOCKCHAIN_C_DATA_TIMESTAMP_H +#define __GRADIDO_BLOCKCHAIN_C_DATA_TIMESTAMP_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct grdd_timestamp +{ + int64_t seconds; + int32_t nanos; +} grdd_timestamp; + +inline bool grdd_timestamp_empty(const grdd_timestamp* timestamp) { + return !timestamp->seconds && !timestamp->nanos; +} +inline bool grdd_timestamp_eq(const grdd_timestamp* t1, grdd_timestamp* t2) { + return t1->seconds == t2->seconds && t1->nanos == t2->nanos; +} +inline bool grdd_timestamp_gt(const grdd_timestamp* t1, const grdd_timestamp* t2) { + return t1->seconds > t2->seconds || t1->seconds == t2->seconds && t1->nanos > t2->nanos; +} +inline bool grdd_timestamp_lt(const grdd_timestamp* t1, const grdd_timestamp* t2) { + return t1->seconds < t2->seconds || t1->seconds == t2->seconds && t1->nanos < t2->nanos; +} +inline grdd_timestamp grdd_timestamp_sub(const grdd_timestamp* t1, grdd_timestamp* t2) { + grdd_timestamp result{.seconds = t1->seconds - t2->seconds, .nanos = t1->nanos - t2->nanos}; + return result; +} + +#ifdef __cplusplus +} +#endif + +#endif // __GRADIDO_BLOCKCHAIN_C_DATA_TIMESTAMP_H \ No newline at end of file diff --git a/dlt-connector/c/grdd/grdd_transaction_type.h b/dlt-connector/c/grdd/grdd_transaction_type.h new file mode 100644 index 000000000..83a0540ea --- /dev/null +++ b/dlt-connector/c/grdd/grdd_transaction_type.h @@ -0,0 +1,56 @@ +#ifndef GRADIDO_BLOCKCHAIN_C_DATA_TRANSACTION_TYPE_H +#define GRADIDO_BLOCKCHAIN_C_DATA_TRANSACTION_TYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \addtogroup enums + * @{ + */ + +/*! + * \enum grdd_transaction_type + * Enum for different transaction types + * !!! don't change order + */ +enum grdd_transaction_type { + //! Invalid or Empty Transaction + GRDD_TRANSACTION_TYPE_NONE = 0, + + //! Creation Transaction, creates new Gradidos + GRDD_TRANSACTION_TYPE_CREATION, + + //! Transfer Transaction, move Gradidos from one account to another + GRDD_TRANSACTION_TYPE_TRANSFER, + + //! Group Friends Update Transaction, update relationship between groups + GRDD_TRANSACTION_TYPE_COMMUNITY_FRIENDS_UPDATE, + + //! Register new address or sub address to group or move address to another group + GRDD_TRANSACTION_TYPE_REGISTER_ADDRESS, + + //! Special Transfer Transaction with timeout used for Gradido Link + GRDD_TRANSACTION_TYPE_DEFERRED_TRANSFER, + + //! First Transaction in Blockchain + GRDD_TRANSACTION_TYPE_COMMUNITY_ROOT, + + //! Redeeming deferred transfer + GRDD_TRANSACTION_TYPE_REDEEM_DEFERRED_TRANSFER, + + //! Timeout deferred transfer, send back locked gdds + GRDD_TRANSACTION_TYPE_TIMEOUT_DEFERRED_TRANSFER, + + //! Technical type for using it in for loops, as max index + GRDD_TRANSACTION_TYPE_MAX_VALUE +}; + +/*! @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* GRADIDO_BLOCKCHAIN_C_DATA_TRANSACTION_TYPE_H */ \ No newline at end of file diff --git a/dlt-connector/c/grdl/grdl_unit.c b/dlt-connector/c/grdl/grdl_unit.c new file mode 100644 index 000000000..90f68ad38 --- /dev/null +++ b/dlt-connector/c/grdl/grdl_unit.c @@ -0,0 +1,123 @@ +#include "grdl_unit.h" + +#include +#include +#include + +const double SECONDS_PER_YEAR = 31556952.0; // seconds in a year in gregorian calender +const grdd_timestamp DECAY_START_TIME = (grdd_timestamp){.seconds = 1620927991, .nanos = 0}; + +double roundToPrecision(double gdd, uint8_t precision) +{ + double factor = pow(10.0, precision); + return round(gdd * factor) / factor; +} + +grdl_unit grdl_unit_from_decimal(double gdd) +{ + grdl_unit gradidoUnit = { + (int64_t)(roundToPrecision(gdd, 4) * 10000.0) + }; + return gradidoUnit; +} + +grdl_unit grdl_unit_from_string(const char* gdd_string) +{ + if (!gdd_string) return (grdl_unit){0}; + char* end; + double gdd_double = strtod(gdd_string, &end); + if (end == gdd_string || *end != '\0') { + // invalid string + return (grdl_unit){0}; + } + return grdl_unit_from_decimal(gdd_double); +} + +int grdl_unit_to_string(const grdl_unit* u, char* buffer, size_t bufferSize, uint8_t precision) +{ + if (precision > 4) return 1; // C hat keine Exceptions + + // Convert to double + double decimal = (double)(u->gradidoCent) / 10000.0; + + // Round down like Node.js if precision < 4 + if (precision < 4) { + double factor = pow(10.0, precision); + decimal = round(decimal * factor) / factor; + } + + // Write to buffer + int written = snprintf(buffer, bufferSize, "%.*f", precision, decimal); + + // snprintf returns number of chars that would have been written (excluding null) + // snprintf return negative value on encoding error + if (written < 0) return 2; + if ((size_t)written < bufferSize) { + return 0; + } + return bufferSize - written; +} + +grdl_unit grdl_unit_calculate_decay(const grdl_unit* u, int64_t seconds) +{ + if (seconds == 0) return (grdl_unit){u->gradidoCent}; + + // decay for one year is 50% + /* + * while (seconds >= SECONDS_PER_YEAR) { + mGradidoCent *= 0.5; + seconds -= SECONDS_PER_YEAR; + } + */ + int64_t gradidoCent = u->gradidoCent; + // optimize version from above + if (seconds >= SECONDS_PER_YEAR) { + uint64_t times = (uint64_t)(seconds / SECONDS_PER_YEAR); + seconds = seconds - times * SECONDS_PER_YEAR; + gradidoCent = u->gradidoCent >> times; + if (!seconds) return (grdl_unit){gradidoCent}; + } +// */ + /*! + * calculate decay factor with compound interest formula converted to q
+ * n = (lg Kn - lg K0) / lg q =>
+ * lg q = (lg Kn - lg K0) / n =>
+ * q = e^((lg Kn - lg K0) / n)
+ *
+ * with: + *
    + *
  • q = decay_factor
  • + *
  • n = days_per_year * 60 * 60 * 24 = seconds per year
  • + *
  • Kn = 50 (capital after a year)
  • + *
  • K0 = 100 (capital at start)
  • + *
+ * further simplified: + * lg 50 - lg 100 = lg 2 => + * q = e^(lg 2 / n) = 2^(x/n) + * with x as seconds in which decay occured + */ + // https://www.wolframalpha.com/input?i=%28e%5E%28lg%282%29+%2F+31556952%29%29%5Ex&assumption=%7B%22FunClash%22%2C+%22lg%22%7D+-%3E+%7B%22Log%22%7D + // from wolframalpha, based on the interest rate formula + return (grdl_unit){((int64_t)((double)(gradidoCent) * pow(2.0, (double)((double)(-seconds) / SECONDS_PER_YEAR))))}; +} + +bool grdl_unit_calculate_duration_seconds( + const grdd_timestamp* startTime, + const grdd_timestamp* endTime, + int64_t* outSeconds +) { + if (!outSeconds) { + return false; + } + if(grdd_timestamp_gt(startTime, endTime) { + return false; + } + grdd_timestamp start = grdd_timestamp_gt(startTime, &DECAY_START_TIME) ? *startTime : DECAY_START_TIME; + grdd_timestamp end = grdd_timestamp_gt(endTime, &DECAY_START_TIME) ? *endTime : DECAY_START_TIME; + if (grdd_timestamp_eq(&start, &end)) { + *outSeconds = 0; + return true; + } + *outSeconds = grdd_timestamp_sub(&end, &start).seconds; + return true; +} diff --git a/dlt-connector/c/grdl/grdl_unit.h b/dlt-connector/c/grdl/grdl_unit.h new file mode 100644 index 000000000..66a658e1b --- /dev/null +++ b/dlt-connector/c/grdl/grdl_unit.h @@ -0,0 +1,84 @@ +#ifndef __GRADIDO_BLOCKCHAIN_C_LOGIC_UNIT_H +#define __GRADIDO_BLOCKCHAIN_C_LOGIC_UNIT_H + +#include "../grdd/grdd_timestamp.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct grdl_unit +{ + int64_t gradidoCent; +} grdl_unit; + +grdl_unit grdl_unit_from_decimal(double gdd); +grdl_unit grdl_unit_from_string(const char* gdd_string); + +//! \return 0 for ok, 1 for invalid precision, 2 for printf encoding error +// and -x if string buffer wasn't big enough where x is the number of missing bytes +int grdl_unit_to_string(const grdl_unit* u, char* buffer, size_t bufferSize, uint8_t precision); + +inline grdl_unit grdl_unit_negated(const grdl_unit* u) +{ + grdl_unit gradidoUnit = {u->gradidoCent}; + gradidoUnit.gradidoCent *= -1; + return gradidoUnit; +} + +inline void grdl_unit_negate(grdl_unit* u) +{ + if (u) u->gradidoCent = -u->gradidoCent; +} + +static inline grdl_unit grdl_unit_zero() +{ + return (grdl_unit){0}; +} +//! return false if startTime > endTime +bool grdl_unit_calculate_duration_seconds( + const grdd_timestamp* startTime, + const grdd_timestamp* endTime, + int64_t* outSeconds +); + +grdl_unit grdl_unit_calculate_decay(const grdl_unit* u, int64_t seconds); + +inline grdl_unit grdl_unit_calculate_decay_timestamp( + const grdl_unit* u, + const grdd_timestamp* startTime, + const grdd_timestamp* endTime +) { + int64_t seconds = 0; + if(!grdl_unit_calculate_duration_seconds(startTime, endTime, &seconds)) { + return (grdl_unit){0}; + } + return grdl_unit_calculate_decay(u, seconds); +} + +inline grdl_unit grld_unit_calculate_compound_interest(const grdl_unit* u, int64_t seconds) { + return grdl_unit_calculate_decay(u, -seconds); +} + +inline grdl_unit grld_unit_calculate_compound_interest_timestamp( + const grdl_unit* u, + const grdd_timestamp* startTime, + const grdd_timestamp* endTime +) { + int64_t seconds = 0; + if(!grdl_unit_calculate_duration_seconds(startTime, endTime, &seconds)) { + return (grdl_unit){0}; + } + return grdl_unit_calculate_decay(u, -seconds); +} + +#ifdef __cplusplus +} +#endif + + +#endif // __GRADIDO_BLOCKCHAIN_C_LOGIC_UNIT_H \ No newline at end of file diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 84ed03df7..518e17418 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -18,6 +18,7 @@ "lint:fix": "biome check --error-on-warnings . --write" }, "dependencies": { + "bun-zigar": "^0.15.2", "cross-env": "^7.0.3", "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#f265dbb1780a912cf8b0418dfe3eaf5cdc5b51cf" }, diff --git a/dlt-connector/zig/hello.zig b/dlt-connector/zig/hello.zig new file mode 100644 index 000000000..36bc9b556 --- /dev/null +++ b/dlt-connector/zig/hello.zig @@ -0,0 +1,5 @@ +const std = @import("std"); + +pub fn hello() void { + std.debug.print("Hello world!", .{}); +}