From 4faf8b0f2ea99bb2ab2a63a1daa7e68efc67bc74 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Fri, 1 Dec 2023 04:04:57 -0600 Subject: [PATCH] update dart interface from cypherstack/sparkmobile main with minor changes eg EXPORT_DART->FFI_PLUGIN_EXPORT add missing streams import (for CDataStream) and formatting --- src/flutter_libsparkmobile.cpp | 264 +++++++++---- src/flutter_libsparkmobile.h | 151 +++++-- src/utils.cpp | 703 +++++++++++++++++++++++++-------- src/utils.h | 38 +- 4 files changed, 887 insertions(+), 269 deletions(-) diff --git a/src/flutter_libsparkmobile.cpp b/src/flutter_libsparkmobile.cpp index c869e91..883eca0 100644 --- a/src/flutter_libsparkmobile.cpp +++ b/src/flutter_libsparkmobile.cpp @@ -3,109 +3,237 @@ #include "deps/sparkmobile/include/spark.h" #include +#include "deps/sparkmobile/bitcoin/uint256.h" #include // Just for printing. using namespace spark; - /* * FFI-friendly wrapper for spark::getAddress. + * + * getAddress: https://github.com/firoorg/sparkmobile/blob/8bf17cd3deba6c3b0d10e89282e02936d7e71cdd/src/spark.cpp#L388 */ FFI_PLUGIN_EXPORT const char* getAddress(const char* keyDataHex, int index, int diversifier, int isTestNet) { - try { - // Use the hex string directly to create the SpendKey. - spark::SpendKey spendKey = createSpendKeyFromData(keyDataHex, index); + try { + // Use the hex string directly to create the SpendKey. + spark::SpendKey spendKey = createSpendKeyFromData(keyDataHex, index); - spark::FullViewKey fullViewKey(spendKey); - spark::IncomingViewKey incomingViewKey(fullViewKey); - spark::Address address(incomingViewKey, static_cast(diversifier)); + spark::FullViewKey fullViewKey(spendKey); + spark::IncomingViewKey incomingViewKey(fullViewKey); + spark::Address address(incomingViewKey, static_cast(diversifier)); - // Encode the Address object into a string using the appropriate network. - std::string encodedAddress = address.encode(isTestNet ? spark::ADDRESS_NETWORK_TESTNET : spark::ADDRESS_NETWORK_MAINNET); + // Encode the Address object into a string using the appropriate network. + std::string encodedAddress = address.encode(isTestNet ? spark::ADDRESS_NETWORK_TESTNET : spark::ADDRESS_NETWORK_MAINNET); - // Allocate memory for the C-style string. - char* cstr = new char[encodedAddress.length() + 1]; - std::strcpy(cstr, encodedAddress.c_str()); + // Allocate memory for the C-style string. + char* cstr = new char[encodedAddress.length() + 1]; + std::strcpy(cstr, encodedAddress.c_str()); - return cstr; - } catch (const std::exception& e) { - std::cerr << "Exception: " << e.what() << std::endl; - return nullptr; - } + return cstr; + } catch (const std::exception& e) { + std::cerr << "Exception: " << e.what() << std::endl; + return nullptr; + } } /* * FFI-friendly wrapper for spark:identifyCoin. * - * Uses the utility functions spark::Coin fromFFI(const CCoin& c_struct) to pass parameters to the - * C++ function spark::identifyCoin(const Coin& coin), then uses the utility function - * CIdentifiedCoinData toFFI(const spark::IdentifiedCoinData& cpp_struct) to convert the result back - * to a C struct. - * - * We also need the incoming view key or we need to derive it, so accept keyDataHex and index. + * identifyCoin: https://github.com/firoorg/sparkmobile/blob/8bf17cd3deba6c3b0d10e89282e02936d7e71cdd/src/spark.cpp#L400 */ FFI_PLUGIN_EXPORT struct CIdentifiedCoinData identifyCoin(struct CCoin c_struct, const char* keyDataHex, int index) { - try { - spark::Coin coin = fromFFI(c_struct); + try { + spark::Coin coin = fromFFI(c_struct); - // Derive the incoming view key from the key data and index. - spark::SpendKey spendKey = createSpendKeyFromData(keyDataHex, index); - spark::FullViewKey fullViewKey(spendKey); - spark::IncomingViewKey incomingViewKey(fullViewKey); + // Derive the incoming view key from the key data and index. + spark::SpendKey spendKey = createSpendKeyFromData(keyDataHex, index); + spark::FullViewKey fullViewKey(spendKey); + spark::IncomingViewKey incomingViewKey(fullViewKey); - spark::IdentifiedCoinData identifiedCoinData = coin.identify(incomingViewKey); - return toFFI(identifiedCoinData); - } catch (const std::exception& e) { - std::cerr << "Exception: " << e.what() << std::endl; - return CIdentifiedCoinData(); - } + spark::IdentifiedCoinData identifiedCoinData = coin.identify(incomingViewKey); + return toFFI(identifiedCoinData); + } catch (const std::exception& e) { + std::cerr << "Exception: " << e.what() << std::endl; + return CIdentifiedCoinData(); + } } /* * FFI-friendly wrapper for spark::createSparkMintRecipients. + * + * createSparkMintRecipients: https://github.com/firoorg/sparkmobile/blob/8bf17cd3deba6c3b0d10e89282e02936d7e71cdd/src/spark.cpp#L43 */ FFI_PLUGIN_EXPORT struct CCRecipient* createSparkMintRecipients( - int numRecipients, - struct PubKeyScript* pubKeyScripts, - uint64_t* amounts, - const char* memo, - int subtractFee) -{ - try { - std::vector recipients; + struct CMintedCoinData* cOutputs, + int outputsLength, + const char* serial_context, + int serial_contextLength, + int generate +) { + // Construct vector of spark::MintedCoinData. + std::vector outputs; - for (int i = 0; i < numRecipients; i++) { - CScript scriptPubKey = createCScriptFromBytes( - pubKeyScripts[i].bytes, - pubKeyScripts[i].length - ); - - CRecipient recipient; - recipient.pubKey = scriptPubKey; - - recipient.amount = amounts[i]; - - recipient.subtractFeeFromAmount = (bool)subtractFee; - - recipients.push_back(recipient); + // Copy the data from the array to the vector. + for (int i = 0; i < outputsLength; i++) { + outputs.push_back(fromFFI(cOutputs[i])); } - std::vector ccRecipients; + // Construct vector of unsigned chars. + std::vector blankSerialContext; - for (const CRecipient& recipient : recipients) { - CCRecipient ccRecipient = toFFI(recipient); - ccRecipients.push_back(ccRecipient); + // Copy the data from the array to the vector. + for (int i = 0; i < serial_contextLength; i++) { + blankSerialContext.push_back(serial_context[i]); } - CCRecipient* result = new CCRecipient[numRecipients]; - std::copy(ccRecipients.begin(), ccRecipients.end(), result); + // Call spark::createSparkMintRecipients. + std::vector recipients = createSparkMintRecipients(outputs, blankSerialContext, generate); - return result; - } catch (const std::exception& e) { - std::cerr << "Exception: " << e.what() << std::endl; - return nullptr; - } + // Create a CRecipient* array. + CCRecipient* cRecipients = new CCRecipient[recipients.size()]; + + // Copy the data from the vector to the array. + for (int i = 0; i < recipients.size(); i++) { + cRecipients[i] = toFFI(recipients[i]); + } + + // Return the array. + return cRecipients; +} + +/* + * FFI-friendly wrapper for spark::createSparkSpendTransaction. + * + * createSparkSpendTransaction: https://github.com/firoorg/sparkmobile/blob/23099b0d9010a970ad75b9cfe05d568d634088f3/src/spark.cpp#L190 + */ +FFI_PLUGIN_EXPORT +unsigned char* cCreateSparkSpendTransaction( + const char* keyDataHex, + int index, + struct CRecip* recipients, // This CRecip(ient) is not the same as a CRecipient. + int recipientsLength, + struct COutputRecipient* privateRecipients, + int privateRecipientsLength, + struct CCSparkMintMeta* coins, + int coinsLength, + struct CCoverSets* cover_set_data_all, + int cover_set_data_allLength, + // idAndBlockHashes_all is unused in spark::createSparkSpendTransaction so we ignore it here. + const char* txHashSig, // A hex string. + int txHashSigLength, + uint64_t fee, + // spark's createSparkSpendTransaction returns void, writing to the serializedSpend parameter. + // We return it instead. + const OutputScript* outputScripts, + int outputScriptsLength +) { + try { + // Derive the keys from the key data and index. + spark::SpendKey spendKey = createSpendKeyFromData(keyDataHex, index); + spark::FullViewKey fullViewKey(spendKey); + spark::IncomingViewKey incomingViewKey(fullViewKey); + + // Convert CRecipient* recipients to std::vector> cppRecipients. + std::vector> cppRecipients; + for (int i = 0; i < recipientsLength; i++) { + cppRecipients.push_back(std::make_pair(recipients[i].amount, recipients[i].subtractFee)); + } + + // Convert COutputRecipient* privateRecipients to std::vector> cppPrivateRecipients. + std::vector> cppPrivateRecipients; + for (int i = 0; i < privateRecipientsLength; i++) { + cppPrivateRecipients.push_back(std::make_pair(fromFFI(privateRecipients[i].output), privateRecipients[i].subtractFee)); + } + + // Convert CCSparkMintMeta* coins to std::list cppCoins. + std::list cppCoins; + for (int i = 0; i < coinsLength; i++) { + cppCoins.push_back(fromFFI(coins[i])); + } + + // Convert CCoverSets* cover_set_data_all to a std::unordered_map cppCoverSetDataAll + // TODO verify correctness. + std::unordered_map cppCoverSetDataAll; + for (int i = 0; i < cover_set_data_allLength; i++) { + for (int j = 0; j < cover_set_data_all[i].cover_setsLength; j++) { + // Convert CCoverSetData to vector of Coins. + std::vector cppCoverSetCoins; + spark::Coin coin = fromFFI(*cover_set_data_all[i].cover_sets[j].cover_set[0]); + cppCoverSetCoins.push_back(coin); + + // Convert CCoverSetData to vector of vector of unsigned chars. + std::vector coverSets(cover_set_data_all[i].cover_sets, cover_set_data_all[i].cover_sets + cover_set_data_all[i].cover_setsLength); + + // Combine all the cover set representations into one vector. + std::vector coverSetReps; + for (int k = 0; k < cover_set_data_all[i].cover_setsLength; k++) { + for (int l = 0; l < cover_set_data_all[i].cover_sets[k].cover_set_representationLength; l++) { + coverSetReps.push_back(cover_set_data_all[i].cover_sets[k].cover_set_representation[l]); + } + } + + // Construct spark::CoverSetData. + spark::CoverSetData cppCoverSetData; + cppCoverSetData.cover_set = cppCoverSetCoins; + cppCoverSetData.cover_set_representation = coverSetReps; + + cppCoverSetDataAll[cover_set_data_all[i].cover_sets[j].cover_setLength] = cppCoverSetData; + } + } + + // Convert const char * txHashSig to a uint256 cppTxHashSig. + // uint256 cppTxHashSig(txHashSig); // This throws `error: no matching function for call to ‘uint256::uint256(const char*&)’`, we need to: + uint256 cppTxHashSig; + cppTxHashSig.SetHex(txHashSig); + + // Make a CAmount cppFee from fee. + CAmount cppFee = fee; + + // Make a dummy for idAndBlockHashes_all. + std::map cppIdAndBlockHashesAll; + + // Make a placeholder for serializedSpend. + std::vector cppSerializedSpend; + + // Convert outputScripts to std::vector> cppOutputScripts. + std::vector> cppOutputScripts; + for (int i = 0; i < outputScriptsLength; i++) { + for (int j = 0; j < outputScripts[i].length; j++) { + cppOutputScripts[i].push_back(outputScripts[i].bytes[j]); + } + } + + // Call spark::createSparkSpendTransaction. + createSparkSpendTransaction( + spendKey, + fullViewKey, + incomingViewKey, + cppRecipients, + cppPrivateRecipients, + cppCoins, + cppCoverSetDataAll, + cppIdAndBlockHashesAll, + cppTxHashSig, + cppFee, + cppSerializedSpend, + cppOutputScripts + ); + + // Allocate memory for the C-style string. + unsigned char* cstr = new unsigned char[cppSerializedSpend.size()]; + + // Copy the data from the vector to the array. + for (int i = 0; i < cppSerializedSpend.size(); i++) { + cstr[i] = cppSerializedSpend[i]; + } + + // Return the array. + return cstr; + } catch (const std::exception& e) { + std::cerr << "Exception: " << e.what() << std::endl; + return nullptr; + } } diff --git a/src/flutter_libsparkmobile.h b/src/flutter_libsparkmobile.h index dd86981..bd02eb1 100644 --- a/src/flutter_libsparkmobile.h +++ b/src/flutter_libsparkmobile.h @@ -1,4 +1,3 @@ - #ifndef ORG_FIRO_SPARK_DART_INTERFACE_H #define ORG_FIRO_SPARK_DART_INTERFACE_H @@ -15,10 +14,6 @@ #endif #endif - -/* - * FFI-friendly wrapper for spark::getAddress. - */ FFI_PLUGIN_EXPORT const char* getAddress(const char* keyDataHex, int index, int diversifier, int isTestNet); @@ -33,15 +28,13 @@ const char* createIncomingViewKey(const char* keyData, int index); /* * FFI-friendly wrapper for a spark::Coin. * - * A Coin is a type, a key, an index, a value, a memo, and a serial context. We accept these params - * as a C struct, deriving the key from the keyData and index. + * Coin: https://github.com/firoorg/sparkmobile/blob/8bf17cd3deba6c3b0d10e89282e02936d7e71cdd/src/coin.h#L66 */ struct CCoin { char type; const unsigned char* k; int kLength; - const char* keyData; - int index; + const char* address; uint64_t v; const unsigned char* memo; int memoLength; @@ -52,8 +45,7 @@ struct CCoin { /* * FFI-friendly wrapper for a spark::IdentifiedCoinData. * - * An IdentifiedCoinData is a diversifier, encrypted diversifier, value, nonce, and memo. We accept - * these params as a C struct. + * IdentifiedCoinData: https://github.com/firoorg/sparkmobile/blob/8bf17cd3deba6c3b0d10e89282e02936d7e71cdd/src/coin.h#L19 */ struct CIdentifiedCoinData { uint64_t i; @@ -68,6 +60,8 @@ struct CIdentifiedCoinData { /* * FFI-friendly wrapper for spark::identifyCoin. + * + * identifyCoin: https://github.com/firoorg/sparkmobile/blob/8bf17cd3deba6c3b0d10e89282e02936d7e71cdd/src/spark.cpp#L400 */ FFI_PLUGIN_EXPORT struct CIdentifiedCoinData identifyCoin(struct CCoin c_struct, const char* keyDataHex, int index); @@ -75,9 +69,7 @@ struct CIdentifiedCoinData identifyCoin(struct CCoin c_struct, const char* keyDa /* * FFI-friendly wrapper for a spark::CRecipient. * - * A CRecipient is a CScript, CAmount, and a bool. We accept a C-style, FFI-friendly CCRecipient - * struct in order to construct a C++ CRecipient. A CScript is constructed from a hex string, a - * CAmount is just a uint64_t, and the bool will be an int. + * CRecipient: https://github.com/firoorg/sparkmobile/blob/8bf17cd3deba6c3b0d10e89282e02936d7e71cdd/include/spark.h#L27 */ struct CCRecipient { const unsigned char* pubKey; @@ -89,9 +81,7 @@ struct CCRecipient { /* * FFI-friendly wrapper for a spark::MintedCoinData. * - * A MintedCoinData is a struct that contains an Address, a uint64_t value, and a string memo. We - * accept these as a CMintedCoinData from the Dart interface, and convert them to a MintedCoinData - * struct. + * MintedCoinData: https://github.com/firoorg/sparkmobile/blob/8bf17cd3deba6c3b0d10e89282e02936d7e71cdd/src/mint_transaction.h#L12 */ struct CMintedCoinData { const char* address; @@ -106,13 +96,128 @@ struct PubKeyScript { /* * FFI-friendly wrapper for spark::createSparkMintRecipients. + * + * createSparkMintRecipients: https://github.com/firoorg/sparkmobile/blob/8bf17cd3deba6c3b0d10e89282e02936d7e71cdd/src/spark.cpp#L43 */ FFI_PLUGIN_EXPORT struct CCRecipient* createSparkMintRecipients( - int numRecipients, - struct PubKeyScript* pubKeyScripts, - uint64_t* amounts, - const char* memo, - int subtractFee); + struct CMintedCoinData* outputs, + int outputsLength, + const char* serial_context, + int serial_contextLength, + int generate); -#endif //ORG_FIRO_SPARK_DART_INTERFACE_H +/* + * FFI-friendly wrapper for a std::pair. + * + * Note this is an ambiguation of a spark::CRecipient. This CRecip(ient) is just a wrapper for a + * CAmount and bool pair, and is not the same as the spark::CRecipient struct above, which gets + * wrapped for us as a CCRecipient and is unrelated to this struct. + * + * See https://github.com/firoorg/sparkmobile/blob/23099b0d9010a970ad75b9cfe05d568d634088f3/src/spark.cpp#L190 + */ +struct CRecip { + uint64_t amount; + int subtractFee; +}; + +/* + * FFI-friendly wrapper for a spark::OutputCoinData. + * + * OutputCoinData: https://github.com/firoorg/sparkmobile/blob/8bf17cd3deba6c3b0d10e89282e02936d7e71cdd/src/spend_transaction.h#L33 + */ +struct COutputCoinData { + const char* address; + uint64_t value; + const char* memo; +}; + +/* + * FFI-friendly wrapper for a . + * + * See https://github.com/firoorg/sparkmobile/blob/23099b0d9010a970ad75b9cfe05d568d634088f3/src/spark.cpp#L195 + */ +struct COutputRecipient { + struct COutputCoinData output; + int subtractFee; +}; + +/* + * FFI-friendly wrapper for a spark::CSparkMintMeta. + * + * CSparkMintMeta: https://github.com/firoorg/sparkmobile/blob/8bf17cd3deba6c3b0d10e89282e02936d7e71cdd/src/primitives.h#L9 + */ +struct CCSparkMintMeta { + uint64_t height; + const char* id; + int isUsed; + const char* txid; + uint64_t i; // Diversifier. + const unsigned char* d; // Encrypted diversifier. + int dLength; + uint64_t v; // Value. + const unsigned char* k; // Nonce. + int kLength; + const char* memo; + int memoLength; + unsigned char* serial_context; + int serial_contextLength; + char type; + CDataStream coin; + + CCSparkMintMeta(uint64_t height, const char* id, int isUsed, const char* txid, uint64_t i, const unsigned char* d, int dLength, uint64_t v, const unsigned char* k, int kLength, const char* memo, int memoLength, unsigned char* serial_context, int serial_contextLength, char type, const CDataStream& coinData); + ~CCSparkMintMeta(); +}; + +/* + * FFI-friendly wrapper for a spark::CoverSetData. + * + * CoverSetData: https://github.com/firoorg/sparkmobile/blob/8bf17cd3deba6c3b0d10e89282e02936d7e71cdd/src/spend_transaction.h#L28 + */ +struct CCoverSetData { + CDataStream** cover_set; // vs. struct CCoin* cover_set; + int cover_setLength; + const unsigned char* cover_set_representation; + int cover_set_representationLength; +}; + +/* + * FFI-friendly wrapper for a std::unordered_map. + * + * See https://github.com/firoorg/sparkmobile/blob/23099b0d9010a970ad75b9cfe05d568d634088f3/src/spark.cpp#L197 + */ +struct CCoverSets { + struct CCoverSetData* cover_sets; + int cover_setsLength; +}; + +struct OutputScript { + unsigned char* bytes; + int length; +}; + +/* + * FFI-friendly wrapper for spark::createSparkSpendTransaction. + * + * createSparkSpendTransaction: https://github.com/firoorg/sparkmobile/blob/23099b0d9010a970ad75b9cfe05d568d634088f3/src/spark.cpp#L190 + */ +FFI_PLUGIN_EXPORT +unsigned char* cCreateSparkSpendTransaction( + const char* keyDataHex, + int index, + struct CRecip* recipients, + int recipientsLength, + struct COutputRecipient* privateRecipients, + int privateRecipientsLength, + struct CCSparkMintMeta* coins, + int coinsLength, + struct CCoverSets* cover_set_data_all, + int cover_set_data_allLength, + const char* txHashSig, + int txHashSigLength, + uint64_t fee, + const OutputScript* outputScripts, + int outputScriptsLength +); + +#endif //ORG_FIRO_SPARK_DART_INTERFACE_H \ No newline at end of file diff --git a/src/utils.cpp b/src/utils.cpp index 0c8d3ad..4ccb937 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -6,7 +6,6 @@ #include #include - #include "flutter_libsparkmobile.h" #include "deps/sparkmobile/src/coin.h" #include "deps/sparkmobile/src/keys.h" @@ -15,42 +14,42 @@ /* * Utility function to generate an address from keyData, index, and a diversifier. */ -const char* getAddressFromData(const char* keyData, int index, const uint64_t diversifier) { - try { - spark::SpendKey spendKey = createSpendKeyFromData(keyData, index); - spark::FullViewKey fullViewKey(spendKey); - spark::IncomingViewKey incomingViewKey(fullViewKey); - spark::Address address(incomingViewKey, diversifier); +const char* getAddressFromData(const char* keyData, int index, const uint64_t diversifier, int isTestNet) { + try { + spark::SpendKey spendKey = createSpendKeyFromData(keyData, index); + spark::FullViewKey fullViewKey(spendKey); + spark::IncomingViewKey incomingViewKey(fullViewKey); + spark::Address address(incomingViewKey, diversifier); - // Encode the Address object into a string. - std::string encodedAddress = address.encode(spark::ADDRESS_NETWORK_TESTNET); + // Encode the Address object into a string. + std::string encodedAddress = address.encode(isTestNet ? spark::ADDRESS_NETWORK_TESTNET : spark::ADDRESS_NETWORK_MAINNET); - // Allocate memory for the C-style string and return it. - char* result = new char[encodedAddress.size() + 1]; - std::copy(encodedAddress.begin(), encodedAddress.end(), result); - result[encodedAddress.size()] = '\0'; // Null-terminate the C string. + // Allocate memory for the C-style string and return it. + char* result = new char[encodedAddress.size() + 1]; + std::copy(encodedAddress.begin(), encodedAddress.end(), result); + result[encodedAddress.size()] = '\0'; // Null-terminate the C string. - return result; - } catch (const std::exception& e) { - return nullptr; - } + return result; + } catch (const std::exception& e) { + return nullptr; + } } /* * Utility function to generate SpendKey from keyData and index. */ spark::SpendKey createSpendKeyFromData(const char *keyData, int index) { - try { - // Convert the keyData from hex string to binary - unsigned char* key_data_bin = hexToBytes(keyData); + try { + // Convert the keyData from hex string to binary + unsigned char* key_data_bin = hexToBytes(keyData); - const SpendKeyData *data = new SpendKeyData(key_data_bin, index); + const SpendKeyData *data = new SpendKeyData(key_data_bin, index); - return createSpendKey(*data); - } catch (const std::exception& e) { - // We can't return here, so just throw the exception again. - throw e; - } + return createSpendKey(*data); + } catch (const std::exception& e) { + // We can't return here, so just throw the exception again. + throw e; + } } /* @@ -58,102 +57,121 @@ spark::SpendKey createSpendKeyFromData(const char *keyData, int index) { * * TODO manage the memory allocated by this function. */ -struct CCoin createCCoin(char type, const unsigned char* k, int kLength, const char* keyData, int index, uint64_t v, const unsigned char* memo, int memoLength, const unsigned char* serial_context, int serial_contextLength) { - CCoin coin; - coin.type = type; - coin.k = copyBytes(k, kLength); - coin.kLength = kLength; - coin.keyData = strdup(keyData); - coin.index = index; - coin.v = v; - coin.memo = copyBytes(memo, memoLength); - coin.memoLength = memoLength; - coin.serial_context = copyBytes(serial_context, serial_contextLength); - coin.serial_contextLength = serial_contextLength; - return coin; +struct CCoin createCCoin(char type, const unsigned char* k, int kLength, const char* address, uint64_t v, const unsigned char* memo, int memoLength, const unsigned char* serial_context, int serial_contextLength) { + CCoin coin; + coin.type = type; + coin.k = copyBytes(k, kLength); + coin.kLength = kLength; + coin.address = address; + coin.v = v; + coin.memo = copyBytes(memo, memoLength); + coin.memoLength = memoLength; + coin.serial_context = copyBytes(serial_context, serial_contextLength); + coin.serial_contextLength = serial_contextLength; + return coin; } /* * Utility function to convert an FFI-friendly C CCoin struct to a C++ Coin struct. */ spark::Coin fromFFI(const CCoin& c_struct) { - spark::Coin cpp_struct( - // The test params are only used for unit tests. - spark::Params::get_default(), - c_struct.type, - spark::Scalar(c_struct.k), - spark::Address(spark::IncomingViewKey(spark::FullViewKey(createSpendKeyFromData(c_struct.keyData, c_struct.index))), c_struct.index), - c_struct.v, - std::string(reinterpret_cast(c_struct.memo), c_struct.memoLength), - std::vector(c_struct.serial_context, c_struct.serial_context + c_struct.serial_contextLength) - ); + spark::Coin cpp_struct( + // The test params are only used for unit tests. + spark::Params::get_default(), + c_struct.type, + spark::Scalar(c_struct.k), + decodeAddress(c_struct.address), + c_struct.v, + std::string(reinterpret_cast(c_struct.memo), c_struct.memoLength), + std::vector(c_struct.serial_context, c_struct.serial_context + c_struct.serial_contextLength) + ); - return cpp_struct; + return cpp_struct; +} + +/* + * Utility function to convert a C++ Coin struct to an FFI-friendly C CDataStream struct. + */ +spark::Coin fromFFI(CDataStream& coinStream) { + spark::Coin coin; + coinStream >> coin; + return coin; +} + +/* + * Utility function to convert a C++ Coin struct to an FFI-friendly C CDataStream struct. + */ +CDataStream toFFI(const spark::Coin& coin) { + // Serialize the Coin object into a CDataStream + CDataStream ccoinStream(SER_NETWORK, PROTOCOL_VERSION); + ccoinStream << coin; + + return ccoinStream; } /* * Utility function to convert a C++ IdentifiedCoinData struct to an FFI-friendly struct. */ CIdentifiedCoinData toFFI(const spark::IdentifiedCoinData& cpp_struct) { - CIdentifiedCoinData c_struct; + CIdentifiedCoinData c_struct; - c_struct.i = cpp_struct.i; - c_struct.d = copyBytes(cpp_struct.d.data(), cpp_struct.d.size()); - c_struct.dLength = cpp_struct.d.size(); - c_struct.v = cpp_struct.v; + c_struct.i = cpp_struct.i; + c_struct.d = copyBytes(cpp_struct.d.data(), cpp_struct.d.size()); + c_struct.dLength = cpp_struct.d.size(); + c_struct.v = cpp_struct.v; - // Serialize and copy the Scalar k. - std::vector scalarBytes(32); - cpp_struct.k.serialize(scalarBytes.data()); - c_struct.k = copyBytes(scalarBytes.data(), scalarBytes.size()); - c_struct.kLength = scalarBytes.size(); + // Serialize and copy the Scalar k. + std::vector scalarBytes(32); + cpp_struct.k.serialize(scalarBytes.data()); + c_struct.k = copyBytes(scalarBytes.data(), scalarBytes.size()); + c_struct.kLength = scalarBytes.size(); - // Copy the memo. - c_struct.memo = strdup(cpp_struct.memo.c_str()); - c_struct.memoLength = cpp_struct.memo.size(); + // Copy the memo. + c_struct.memo = strdup(cpp_struct.memo.c_str()); + c_struct.memoLength = cpp_struct.memo.size(); - return c_struct; + return c_struct; } /* * Factory function to create a CScript from a byte array. */ CScript createCScriptFromBytes(const unsigned char* bytes, int length) { - // Construct a CScript object - CScript script; + // Construct a CScript object + CScript script; - // Check if bytes is not nullptr and length is positive - if (bytes != nullptr && length > 0) { - // Append each byte to the script - for (int i = 0; i < length; ++i) { - script << bytes[i]; - } - } + // Check if bytes is not nullptr and length is positive + if (bytes != nullptr && length > 0) { + // Append each byte to the script + for (int i = 0; i < length; ++i) { + script << bytes[i]; + } + } - return script; + return script; } /* * Utility function to convert a C++ CScript to a byte array. */ std::vector serializeCScript(const CScript& script) { - return std::vector(script.begin(), script.end()); + return std::vector(script.begin(), script.end()); } /* * Utility function to convert an FFI-friendly C CCRecipient struct to a C++ CRecipient struct. */ CRecipient fromFFI(const CCRecipient& c_struct) { - // Use the factory function to create a CScript object. - CScript script = createCScriptFromBytes(c_struct.pubKey, c_struct.pubKeyLength); + // Use the factory function to create a CScript object. + CScript script = createCScriptFromBytes(c_struct.pubKey, c_struct.pubKeyLength); - CRecipient cpp_struct = createCRecipient( - script, - c_struct.cAmount, - static_cast(c_struct.subtractFee) - ); + CRecipient cpp_struct = createCRecipient( + script, + c_struct.cAmount, + static_cast(c_struct.subtractFee) + ); - return cpp_struct; + return cpp_struct; } /* @@ -162,33 +180,33 @@ CRecipient fromFFI(const CCRecipient& c_struct) { * TODO manage the memory allocated by this function. */ struct CCRecipient createCCRecipient(const unsigned char* pubKey, uint64_t amount, int subtractFee) { - CCRecipient recipient; - recipient.pubKey = copyBytes(pubKey, 32); - recipient.cAmount = amount; - recipient.subtractFee = subtractFee; - return recipient; + CCRecipient recipient; + recipient.pubKey = copyBytes(pubKey, 32); + recipient.cAmount = amount; + recipient.subtractFee = subtractFee; + return recipient; } /* * Utility function to convert a C++ CRecipient struct to an FFI-friendly struct. */ CCRecipient toFFI(const CRecipient& cpp_struct) { - CCRecipient c_struct; + CCRecipient c_struct; - // Serialize CScript and copy. - std::vector scriptBytes = serializeCScript(cpp_struct.pubKey); - if (!scriptBytes.empty()) { - c_struct.pubKey = copyBytes(scriptBytes.data(), scriptBytes.size()); - c_struct.pubKeyLength = static_cast(scriptBytes.size()); - } else { - c_struct.pubKey = nullptr; - c_struct.pubKeyLength = 0; - } + // Serialize CScript and copy. + std::vector scriptBytes = serializeCScript(cpp_struct.pubKey); + if (!scriptBytes.empty()) { + c_struct.pubKey = copyBytes(scriptBytes.data(), scriptBytes.size()); + c_struct.pubKeyLength = static_cast(scriptBytes.size()); + } else { + c_struct.pubKey = nullptr; + c_struct.pubKeyLength = 0; + } - c_struct.cAmount = cpp_struct.amount; - c_struct.subtractFee = static_cast(cpp_struct.subtractFeeFromAmount); + c_struct.cAmount = cpp_struct.amount; + c_struct.subtractFee = static_cast(cpp_struct.subtractFeeFromAmount); - return c_struct; + return c_struct; } /* @@ -197,122 +215,463 @@ CCRecipient toFFI(const CRecipient& cpp_struct) { * TODO manage the memory allocated by this function. */ CRecipient createCRecipient(const CScript& script, CAmount amount, bool subtractFee) { - CRecipient recipient; - recipient.pubKey = script; - recipient.amount = amount; - recipient.subtractFeeFromAmount = subtractFee; - return recipient; + CRecipient recipient; + recipient.pubKey = script; + recipient.amount = amount; + recipient.subtractFeeFromAmount = subtractFee; + return recipient; } /* * Utility function to decode an Address from a string. */ spark::Address decodeAddress(const std::string& str) { - spark::Address address; - address.decode(str); + spark::Address address; + address.decode(str); - return address; + return address; } /* * MintedCoinData factory. */ spark::MintedCoinData createMintedCoinData(const char* address, uint64_t v, const char* memo) { - return { - decodeAddress(address), - v, - memo - }; + return { + decodeAddress(address), + v, + memo + }; } /* * Utility function to convert an FFI-friendly C CMintedCoinData struct to a C++ MintedCoinData. */ spark::MintedCoinData fromFFI(const CMintedCoinData& c_struct) { - return createMintedCoinData( - c_struct.address, - c_struct.value, - c_struct.memo - ); + return createMintedCoinData( + c_struct.address, + c_struct.value, + c_struct.memo + ); } /* * CMintedCoinData factory. */ CMintedCoinData createCMintedCoinData(const char* address, uint64_t value, const char* memo) { - CMintedCoinData c_struct; - c_struct.address = strdup(address); - c_struct.value = value; - c_struct.memo = strdup(memo); - return c_struct; + CMintedCoinData c_struct; + c_struct.address = strdup(address); + c_struct.value = value; + c_struct.memo = strdup(memo); + return c_struct; } /* * Utility function to convert a C++ MintedCoinData struct to an FFI-friendly CMintedCoinData. */ -CMintedCoinData toFFI(const spark::MintedCoinData& cpp_struct) { - return createCMintedCoinData( - cpp_struct.address.encode(true).c_str(), - cpp_struct.v, - cpp_struct.memo.c_str() - ); +CMintedCoinData toFFI(const spark::MintedCoinData& cpp_struct, int isTestNet) { + CMintedCoinData c_struct; + c_struct.address = strdup(cpp_struct.address.encode(isTestNet ? spark::ADDRESS_NETWORK_TESTNET : spark::ADDRESS_NETWORK_MAINNET).c_str()); + c_struct.value = cpp_struct.v; + c_struct.memo = strdup(cpp_struct.memo.c_str()); + return c_struct; } /* - * Utility function for deep copying byte arrays. - * - * Used by createCCoin. + * OutputCoinData factory. */ -unsigned char* copyBytes(const unsigned char* source, int length) { - if (source == nullptr || length <= 0) return nullptr; +spark::OutputCoinData createOutputCoinData(const char* address, uint64_t v, const char* memo) { + return { + decodeAddress(address), + v, + memo + }; +} - unsigned char* dest = new unsigned char[length]; - std::memcpy(dest, source, length); - return dest; +/* + * Utility function to convert an FFI-friendly C COutputCoinData struct to a C++ OutputCoinData. + */ +spark::OutputCoinData fromFFI(const COutputCoinData& c_struct) { + return createOutputCoinData( + c_struct.address, + c_struct.value, + c_struct.memo + ); +} + +/* + * COutputCoinData factory. + */ +COutputCoinData createCOutputCoinData(const char* address, uint64_t value, const char* memo) { + COutputCoinData c_struct; + c_struct.address = strdup(address); + c_struct.value = value; + c_struct.memo = strdup(memo); + return c_struct; +} + +/* + * Utility function to convert a C++ OutputCoinData struct to an FFI-friendly COutputCoinData. + */ +COutputCoinData toFFI(const spark::OutputCoinData& cpp_struct, int isTestNet) { + // Encode address for testnet + std::string address = cpp_struct.address.encode(isTestNet ? spark::ADDRESS_NETWORK_TESTNET : spark::ADDRESS_NETWORK_MAINNET); + + return createCOutputCoinData( + address.c_str(), + cpp_struct.v, + cpp_struct.memo.c_str() + ); +} + +/* + * CSparkMintMeta factory. + * + * A CSparkMintMeta is a C++ struct that contains a height, id, isUsed, txid, diversifier, encrypted + * diversifier, value, nonce, memo, serial context, type, and coin. We accept these as a + * CCSparkMintMeta from the Dart interface and convert them to a C++ CSparkMintMeta struct. + */ +CSparkMintMeta createCSparkMintMeta( + const uint64_t height, const uint64_t id, const int isUsed, + const char* txidStr, const uint64_t diversifier, + const char* encryptedDiversifierStr, const uint64_t value, + const char* nonceStr, const char* memoStr, + const unsigned char* serialContext, + const int serialContextLength, const char type, const CCoin coin +) { + CSparkMintMeta cpp_struct; + + cpp_struct.nHeight = height; + cpp_struct.nId = id; + cpp_struct.isUsed = isUsed != 0; + + if (txidStr) { + cpp_struct.txid = uint256S(txidStr); + } + + if (encryptedDiversifierStr) { + size_t edLen = std::strlen(encryptedDiversifierStr); + cpp_struct.d = std::vector(encryptedDiversifierStr, encryptedDiversifierStr + edLen); + } + + cpp_struct.i = diversifier; + cpp_struct.v = value; + + if (nonceStr) { + size_t nonceLen = std::strlen(nonceStr); + std::vector nonceBytes(nonceStr, nonceStr + nonceLen); + cpp_struct.k = Scalar(nonceBytes.data()); + } + + if (memoStr) { + cpp_struct.memo = std::string(memoStr); + } + + if (serialContext && serialContextLength > 0) { + cpp_struct.serial_context = std::vector(serialContext, serialContext + serialContextLength); + } + + cpp_struct.type = type; + cpp_struct.coin = fromFFI(coin); + + return cpp_struct; +} + +/* + * Utility function to convert a C++ CSparkMintMeta struct to an FFI-friendly C CCSparkMintMeta. + */ +CSparkMintMeta fromFFI(const CCSparkMintMeta& c_struct) { + CSparkMintMeta cpp_struct; + cpp_struct.nHeight = c_struct.height; + cpp_struct.nId = std::stoull(c_struct.id); + cpp_struct.isUsed = c_struct.isUsed; + cpp_struct.txid = uint256S(c_struct.txid); + cpp_struct.i = c_struct.i; + cpp_struct.d = std::vector(c_struct.d, c_struct.d + c_struct.dLength); + cpp_struct.v = c_struct.v; + cpp_struct.k = bytesToScalar(c_struct.k, c_struct.kLength); + cpp_struct.memo = std::string(c_struct.memo); + cpp_struct.serial_context = std::vector(c_struct.serial_context, + c_struct.serial_context + + c_struct.serial_contextLength); + cpp_struct.type = c_struct.type; + // c_struct.coin is a const, but we need a non-const reference to pass to fromFFI. + // Convert c_struct.coin to a non-const. + CDataStream coin = c_struct.coin; + cpp_struct.coin = fromFFI(coin); + return cpp_struct; +} + +/* + * CCSparkMintMeta constructor. + * + * Needed because CDataStream has no constructor. + */ +CCSparkMintMeta::CCSparkMintMeta(uint64_t height, const char* id, int isUsed, const char* txid, + uint64_t i, const unsigned char* d, int dLength, uint64_t v, + const unsigned char* k, int kLength, const char* memo, + int memoLength, unsigned char* serial_context, + int serial_contextLength, char type, const CDataStream& coinData +) : height(height), isUsed(isUsed), i(i), v(v), dLength(dLength), kLength(kLength), + memoLength(memoLength), serial_contextLength(serial_contextLength), type(type), coin(coinData) +{ + this->id = strdup(id); + this->txid = strdup(txid); + this->d = copyBytes(d, dLength); + this->k = copyBytes(k, kLength); + this->memo = strdup(memo); + this->serial_context = copyBytes(serial_context, serial_contextLength); +} + +/* + * CCSparkMintMeta destructor. + */ +CCSparkMintMeta::~CCSparkMintMeta() { + free(const_cast(id)); + free(const_cast(txid)); + delete[] d; + delete[] k; + free(const_cast(memo)); + delete[] serial_context; +} + +/* + * CCSparkMintMeta factory. + * + * A CSparkMintMeta is a struct that contains a height, id, isUsed, txid, diversifier, encrypted + * diversifier, value, nonce, memo, serial context, type, and coin. We accept these as a + * CCSparkMintMeta from the Dart interface, and convert them to a C++ CSparkMintMeta struct. + */ +CCSparkMintMeta createCCSparkMintMeta(const uint64_t height, const uint64_t id, const int isUsed, const char* txid, const uint64_t diversifier, const char* encryptedDiversifier, const uint64_t value, const char* nonce, const char* memo, const unsigned char* serial_context, const int serial_contextLength, const char type, const CCoin coin) { + // Create a string version of the id + std::string idStr = std::to_string(id); + const char* idCStr = idStr.c_str(); + + // Convert encryptedDiversifier and nonce to unsigned char* + auto encryptedDiversifierCStr = reinterpret_cast(encryptedDiversifier); + auto nonceCStr = reinterpret_cast(nonce); + + // Convert coin to CDataStream + spark::Coin coinStruct = fromFFI(coin); + CDataStream coinStream = toFFI(coinStruct); + + // Construct CCSparkMintMeta using the constructor + return CCSparkMintMeta( + height, + idCStr, + isUsed, + txid, + diversifier, + encryptedDiversifierCStr, + std::strlen(encryptedDiversifier), + value, + nonceCStr, + std::strlen(nonce), + memo, + std::strlen(memo), + const_cast(serial_context), + serial_contextLength, + type, + coinStream + ); +} + +/* + * Utility function to convert an FFI-friendly C CCSparkMintMeta struct to a C++ CSparkMintMeta. + */ +CCSparkMintMeta toFFI(const CSparkMintMeta& cpp_struct) { + // Convert the id, txid, d, k, memo, and serial_context to appropriate types + std::string idStr = std::to_string(cpp_struct.nId); + const char* idCStr = idStr.c_str(); + + CDataStream coinStream = toFFI(cpp_struct.coin); + + std::vector scalarBytes(32); + cpp_struct.k.serialize(scalarBytes.data()); + + return CCSparkMintMeta( + cpp_struct.nHeight, + idCStr, + cpp_struct.isUsed, + cpp_struct.txid.ToString().c_str(), + cpp_struct.i, + copyBytes(cpp_struct.d.data(), cpp_struct.d.size()), + cpp_struct.d.size(), + cpp_struct.v, + copyBytes(scalarBytes.data(), scalarBytes.size()), // Size should be 32. + 32, + strdup(cpp_struct.memo.c_str()), + cpp_struct.memo.size(), + copyBytes(cpp_struct.serial_context.data(), cpp_struct.serial_context.size()), + cpp_struct.serial_context.size(), + cpp_struct.type, + coinStream + ); +} + +/* + * CoverSetData factory. + */ +spark::CoverSetData createCoverSetData( + const std::vector& cover_set, + const std::vector& cover_set_representations +) { + spark::CoverSetData coverSetData; + coverSetData.cover_set = cover_set; + coverSetData.cover_set_representation = cover_set_representations; + return coverSetData; +} + +/* + * Utility function to convert an FFI-friendly C CCoverSetData struct to a C++ CoverSetData. + */ +spark::CoverSetData fromFFI(const CCoverSetData& c_struct) { + std::vector cover_set; + + for (int i = 0; i < c_struct.cover_setLength; i++) { + spark::Coin coin; + CDataStream coinStream = *c_struct.cover_set[i]; + coinStream >> coin; + cover_set.emplace_back(coin); + } + + std::vector cover_set_representation(c_struct.cover_set_representation, c_struct.cover_set_representation + c_struct.cover_set_representationLength); + + return createCoverSetData(cover_set, cover_set_representation); +} + +/* + * CCoverSetData factory. + */ +CCoverSetData createCCoverSetData(const CCoin* cover_set, + const unsigned char* cover_set_representation, + const int cover_set_representationLength) { + std::vector cover_set_streams; + + for (int i = 0; i < cover_set_representationLength; i++) { + // Convert CCoin to Coin. + spark::Coin coin = fromFFI(cover_set[i]); + + // Serialize Coin. + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << coin; + + // Add stream to vector. + cover_set_streams.push_back(stream); + } + + // Create array containing the address of cover_set_streams + CDataStream** cover_set_streams_pp = new CDataStream*[cover_set_representationLength]; + + for (int i = 0; i < cover_set_representationLength; i++) { + cover_set_streams_pp[i] = &cover_set_streams[i]; + } + + // Create the CCoverSetData and set the cover_set. + CCoverSetData c_struct; + + // Assign the pointer to pointer + c_struct.cover_set = cover_set_streams_pp; + + // Assign the cover_set_representation. + c_struct.cover_set_representation = cover_set_representation; + c_struct.cover_set_representationLength = cover_set_representationLength; + return c_struct; +} + +/* + * Utility function to convert a C++ CoverSetData struct to an FFI-friendly CCoverSetData. + * + * This throws. We don't need toFFI yet (except to make complete tests...), so let's just comment + * it out. + * +CCoverSetData toFFI(const spark::CoverSetData& cpp_struct) { + CCoverSetData c_struct; + // Converting the CCoins to spark::Coins. + std::vector cover_set; + for (int i = 0; i < cpp_struct.cover_set.size(); i++) { + cover_set.push_back(fromFFI(cpp_struct.cover_set[i])); // This line throws. + } + + // Serialize the spark::Coins as CDataStreams. + std::vector cover_set_streams; + for (int i = 0; i < cover_set.size(); i++) { + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << cover_set[i]; + cover_set_streams.push_back(stream); + } + + // Convert the std::vector to a CDataStream*. + CDataStream* cover_set_streams_array = &cover_set_streams[0]; + + c_struct.cover_set_representation = cpp_struct.cover_set_representation.data(); + c_struct.cover_set_representationLength = cpp_struct.cover_set_representation.size(); + + for (int i = 0; i < cpp_struct.cover_set.size(); i++) { + c_struct.cover_set[i] = toFFI(cpp_struct.cover_set[i]); + } + + return c_struct; +} + */ + +unsigned char* copyBytes(const unsigned char* source, int length) { + if (source == nullptr || length <= 0) return nullptr; + + unsigned char* dest = new unsigned char[length]; + std::memcpy(dest, source, length); + return dest; +} + +Scalar bytesToScalar(const unsigned char* bytes, int size) { + if (bytes == nullptr || size <= 0) { + throw std::invalid_argument("Invalid byte array for Scalar conversion."); + } + // Assuming Scalar can be constructed from a byte array. + return Scalar(bytes); } unsigned char *hexToBytes(const char *hexstr) { - size_t length = strlen(hexstr) / 2; - auto *chrs = (unsigned char *) malloc((length + 1) * sizeof(unsigned char)); - for (size_t i = 0, j = 0; j < length; i += 2, j++) { - chrs[j] = (hexstr[i] % 32 + 9) % 25 * 16 + (hexstr[i + 1] % 32 + 9) % 25; - } - chrs[length] = '\0'; - return chrs; + size_t length = strlen(hexstr) / 2; + auto *chrs = (unsigned char *) malloc((length + 1) * sizeof(unsigned char)); + for (size_t i = 0, j = 0; j < length; i += 2, j++) { + chrs[j] = (hexstr[i] % 32 + 9) % 25 * 16 + (hexstr[i + 1] % 32 + 9) % 25; + } + chrs[length] = '\0'; + return chrs; } const char *bytesToHex(const unsigned char *bytes, int size) { - std::string str; - for (int i = 0; i < size; ++i) { - const unsigned char ch = bytes[i]; - str.append(&hexArray[(ch & 0xF0) >> 4], 1); - str.append(&hexArray[ch & 0xF], 1); - } - char *new_str = new char[std::strlen(str.c_str()) + 1]; - std::strcpy(new_str, str.c_str()); - return new_str; + std::string str; + for (int i = 0; i < size; ++i) { + const unsigned char ch = bytes[i]; + str.append(&hexArray[(ch & 0xF0) >> 4], 1); + str.append(&hexArray[ch & 0xF], 1); + } + char *new_str = new char[std::strlen(str.c_str()) + 1]; + std::strcpy(new_str, str.c_str()); + return new_str; } const char *bytesToHex(const char *bytes, int size) { - std::string str; - for (int i = 0; i < size; ++i) { - const unsigned char ch = (const unsigned char) bytes[i]; - str.append(&hexArray[(ch & 0xF0) >> 4], 1); - str.append(&hexArray[ch & 0xF], 1); - } - char *new_str = new char[std::strlen(str.c_str()) + 1]; - std::strcpy(new_str, str.c_str()); - return new_str; + std::string str; + for (int i = 0; i < size; ++i) { + const unsigned char ch = (const unsigned char) bytes[i]; + str.append(&hexArray[(ch & 0xF0) >> 4], 1); + str.append(&hexArray[ch & 0xF], 1); + } + char *new_str = new char[std::strlen(str.c_str()) + 1]; + std::strcpy(new_str, str.c_str()); + return new_str; } const char *bytesToHex(std::vector bytes, int size) { - std::string str; - for (int i = 0; i < size; ++i) { - const unsigned char ch = bytes[i]; - str.append(&hexArray[(ch & 0xF0) >> 4], 1); - str.append(&hexArray[ch & 0xF], 1); - } - char *new_str = new char[std::strlen(str.c_str()) + 1]; - std::strcpy(new_str, str.c_str()); - return new_str; + std::string str; + for (int i = 0; i < size; ++i) { + const unsigned char ch = bytes[i]; + str.append(&hexArray[(ch & 0xF0) >> 4], 1); + str.append(&hexArray[ch & 0xF], 1); + } + char *new_str = new char[std::strlen(str.c_str()) + 1]; + std::strcpy(new_str, str.c_str()); + return new_str; } diff --git a/src/utils.h b/src/utils.h index 3bdbb3f..f6bbdcc 100644 --- a/src/utils.h +++ b/src/utils.h @@ -8,16 +8,19 @@ #include "flutter_libsparkmobile.h" #include "deps/sparkmobile/include/spark.h" +#include "deps/sparkmobile/bitcoin/streams.h" // For CDataStream. -const char* getAddressFromData(const char* keyData, int index, const uint64_t diversifier); +const char* getAddressFromData(const char* keyData, int index, const uint64_t diversifier, int isTestNet); spark::SpendKey createSpendKeyFromData(const char *keyData, int index); spark::Coin fromFFI(const CCoin& c_struct); -CCoin toFFI(const spark::Coin& cpp_struct); +spark::Coin fromFFI(CDataStream& coinStream); -struct CCoin createCCoin(char type, const unsigned char* k, int kLength, const char* keyData, int index, uint64_t v, const unsigned char* memo, int memoLength, const unsigned char* serial_context, int serial_contextLength); +struct CCoin createCCoin(char type, const unsigned char* k, int kLength, const char* address, uint64_t v, const unsigned char* memo, int memoLength, const unsigned char* serial_context, int serial_contextLength); + +CDataStream toFFI(const spark::Coin& cpp_struct); spark::IdentifiedCoinData fromFFI(const CIdentifiedCoinData& c_struct); @@ -43,13 +46,37 @@ spark::MintedCoinData fromFFI(const CMintedCoinData& c_struct); CMintedCoinData createCMintedCoinData(const char* address, uint64_t value, const char* memo); -CMintedCoinData toFFI(const spark::MintedCoinData& cpp_struct); +CMintedCoinData toFFI(const spark::MintedCoinData& cpp_struct, int isTestNet); + +spark::OutputCoinData fromFFI(const COutputCoinData& c_struct); + +spark::OutputCoinData createOutputCoinData(const char* address, uint64_t v, const char* memo); + +COutputCoinData createCOutputCoinData(const char* address, uint64_t value, const char* memo); + +COutputCoinData toFFI(const spark::OutputCoinData& cpp_struct, int isTestNet); + +CSparkMintMeta createCSparkMintMeta(const uint64_t height, const uint64_t id, const int isUsed, const char* txid, const uint64_t diversifier, const char* encryptedDiversifier, const uint64_t value, const char* nonce, const char* memo, const unsigned char* serialContext, const int serialContextLength, const char type, const CCoin coin); + +CSparkMintMeta fromFFI(const CCSparkMintMeta& c_struct); + +CCSparkMintMeta createCCSparkMintMeta(const uint64_t height, const uint64_t id, const int isUsed, const char* txid, const uint64_t diversifier, const char* encryptedDiversifier, const uint64_t value, const char* nonce, const char* memo, const unsigned char* serialContext, const int serialContextLength, const char type, const CCoin coin); + +CCSparkMintMeta toFFI(const CSparkMintMeta& cpp_struct); + +spark::CoverSetData createCoverSetData(const std::vector& cover_set, const std::vector>& cover_set_representations); + +spark::CoverSetData fromFFI(const CCoverSetData& c_struct); + +CCoverSetData createCCoverSetData(const CCoin* cover_set, const unsigned char* cover_set_representation, const int cover_set_representationLength); char const hexArray[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', - 'e', 'f'}; + 'e', 'f'}; unsigned char* copyBytes(const unsigned char* source, int length); +Scalar bytesToScalar(const unsigned char* bytes, int size); + unsigned char *hexToBytes(const char *str); const char *bytesToHex(const unsigned char *bytes, int size); @@ -58,5 +85,4 @@ const char *bytesToHex(const char *bytes, int size); const char *bytesToHex(std::vector bytes, int size); - #endif //ORG_FIRO_SPARK_UTILS_H