update dart interface from cypherstack/sparkmobile main

with minor changes eg EXPORT_DART->FFI_PLUGIN_EXPORT

add missing streams import (for CDataStream)

and formatting
This commit is contained in:
sneurlax
2023-12-01 04:04:57 -06:00
parent 85c2327f38
commit 4faf8b0f2e
4 changed files with 887 additions and 269 deletions

View File

@@ -3,109 +3,237 @@
#include "deps/sparkmobile/include/spark.h"
#include <cstring>
#include "deps/sparkmobile/bitcoin/uint256.h"
#include <iostream> // 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<uint64_t>(diversifier));
spark::FullViewKey fullViewKey(spendKey);
spark::IncomingViewKey incomingViewKey(fullViewKey);
spark::Address address(incomingViewKey, static_cast<uint64_t>(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<CRecipient> recipients;
struct CMintedCoinData* cOutputs,
int outputsLength,
const char* serial_context,
int serial_contextLength,
int generate
) {
// Construct vector of spark::MintedCoinData.
std::vector<spark::MintedCoinData> 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<CCRecipient> ccRecipients;
// Construct vector of unsigned chars.
std::vector<unsigned char> 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<CRecipient> 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<std::pair<CAmount, bool>> cppRecipients.
std::vector<std::pair<CAmount, bool>> 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<std::pair<spark::OutputCoinData, bool>> cppPrivateRecipients.
std::vector<std::pair<spark::OutputCoinData, bool>> 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<CSparkMintMeta> cppCoins.
std::list<CSparkMintMeta> 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<uint64_t, spark::CoverSetData> cppCoverSetDataAll
// TODO verify correctness.
std::unordered_map<uint64_t, spark::CoverSetData> 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<spark::Coin> 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<CCoverSetData> 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<unsigned char> 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<uint64_t, uint256> cppIdAndBlockHashesAll;
// Make a placeholder for serializedSpend.
std::vector<uint8_t> cppSerializedSpend;
// Convert outputScripts to std::vector<std::vector<unsigned char>> cppOutputScripts.
std::vector<std::vector<unsigned char>> 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;
}
}

View File

@@ -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<CAmount, bool>.
*
* 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 <spark::OutputCoinData, bool>.
*
* 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<uint64_t, spark::CoverSetData>.
*
* 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

View File

@@ -6,7 +6,6 @@
#include <vector>
#include <string>
#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<const char*>(c_struct.memo), c_struct.memoLength),
std::vector<unsigned char>(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<const char*>(c_struct.memo), c_struct.memoLength),
std::vector<unsigned char>(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<unsigned char> 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<unsigned char> 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<unsigned char> serializeCScript(const CScript& script) {
return std::vector<unsigned char>(script.begin(), script.end());
return std::vector<unsigned char>(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<bool>(c_struct.subtractFee)
);
CRecipient cpp_struct = createCRecipient(
script,
c_struct.cAmount,
static_cast<bool>(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<unsigned char> scriptBytes = serializeCScript(cpp_struct.pubKey);
if (!scriptBytes.empty()) {
c_struct.pubKey = copyBytes(scriptBytes.data(), scriptBytes.size());
c_struct.pubKeyLength = static_cast<int>(scriptBytes.size());
} else {
c_struct.pubKey = nullptr;
c_struct.pubKeyLength = 0;
}
// Serialize CScript and copy.
std::vector<unsigned char> scriptBytes = serializeCScript(cpp_struct.pubKey);
if (!scriptBytes.empty()) {
c_struct.pubKey = copyBytes(scriptBytes.data(), scriptBytes.size());
c_struct.pubKeyLength = static_cast<int>(scriptBytes.size());
} else {
c_struct.pubKey = nullptr;
c_struct.pubKeyLength = 0;
}
c_struct.cAmount = cpp_struct.amount;
c_struct.subtractFee = static_cast<int>(cpp_struct.subtractFeeFromAmount);
c_struct.cAmount = cpp_struct.amount;
c_struct.subtractFee = static_cast<int>(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<unsigned char>(encryptedDiversifierStr, encryptedDiversifierStr + edLen);
}
cpp_struct.i = diversifier;
cpp_struct.v = value;
if (nonceStr) {
size_t nonceLen = std::strlen(nonceStr);
std::vector<unsigned char> 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<unsigned char>(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<unsigned char>(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<unsigned char>(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<char*>(id));
free(const_cast<char*>(txid));
delete[] d;
delete[] k;
free(const_cast<char*>(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<const unsigned char*>(encryptedDiversifier);
auto nonceCStr = reinterpret_cast<const unsigned char*>(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<unsigned char*>(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<unsigned char> 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<spark::Coin>& cover_set,
const std::vector<unsigned char>& 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<spark::Coin> 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<unsigned char> 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<CDataStream> 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<spark::Coin> 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<CDataStream> 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<CDataStream> 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<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;
}

View File

@@ -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<spark::Coin>& cover_set, const std::vector<std::vector<unsigned char>>& 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<unsigned char> bytes, int size);
#endif //ORG_FIRO_SPARK_UTILS_H