mirror of
https://github.com/MAGICGrants/flutter_libsparkmobile.git
synced 2026-01-09 13:08:00 -05:00
WIP mint serial context serialization
This commit is contained in:
@@ -160,6 +160,28 @@ abstract final class LibSpark {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Uint8List serializeMintContext({required List<(String, int)> inputs}) {
|
||||
final inputsPtr =
|
||||
malloc.allocate<DartInputData>(sizeOf<DartInputData>() * inputs.length);
|
||||
|
||||
for (int i = 0; i < inputs.length; i++) {
|
||||
final hash =
|
||||
Uint8List.fromList(inputs[i].$1.to32BytesFromHex().reversed.toList());
|
||||
|
||||
inputsPtr[i].txHashLength = hash.length;
|
||||
inputsPtr[i].txHash = hash.unsignedCharPointer();
|
||||
inputsPtr[i].vout = inputs[i].$2;
|
||||
}
|
||||
|
||||
final result = _bindings.serializeMintContext(inputsPtr, inputs.length);
|
||||
|
||||
final serialized = result.ref.context.toUint8List(result.ref.contextLength);
|
||||
|
||||
// TODO frees
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
///
|
||||
/// Create spark mint recipients
|
||||
///
|
||||
|
||||
@@ -229,6 +229,24 @@ class FlutterLibsparkmobileBindings {
|
||||
late final _selectSparkCoins = _selectSparkCoinsPtr.asFunction<
|
||||
ffi.Pointer<SelectSparkCoinsResult> Function(
|
||||
int, int, ffi.Pointer<CCSparkMintMeta>, int, int)>();
|
||||
|
||||
ffi.Pointer<SerializedMintContextResult> serializeMintContext(
|
||||
ffi.Pointer<DartInputData> inputs,
|
||||
int inputsLength,
|
||||
) {
|
||||
return _serializeMintContext(
|
||||
inputs,
|
||||
inputsLength,
|
||||
);
|
||||
}
|
||||
|
||||
late final _serializeMintContextPtr = _lookup<
|
||||
ffi.NativeFunction<
|
||||
ffi.Pointer<SerializedMintContextResult> Function(
|
||||
ffi.Pointer<DartInputData>, ffi.Int)>>('serializeMintContext');
|
||||
late final _serializeMintContext = _serializeMintContextPtr.asFunction<
|
||||
ffi.Pointer<SerializedMintContextResult> Function(
|
||||
ffi.Pointer<DartInputData>, int)>();
|
||||
}
|
||||
|
||||
/// FFI-friendly wrapper for a spark::Coin.
|
||||
@@ -539,3 +557,20 @@ final class SparkSpendTransactionResult extends ffi.Struct {
|
||||
@ffi.Int()
|
||||
external int isError;
|
||||
}
|
||||
|
||||
final class DartInputData extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.UnsignedChar> txHash;
|
||||
|
||||
@ffi.Int()
|
||||
external int txHashLength;
|
||||
|
||||
@ffi.Int()
|
||||
external int vout;
|
||||
}
|
||||
|
||||
final class SerializedMintContextResult extends ffi.Struct {
|
||||
external ffi.Pointer<ffi.UnsignedChar> context;
|
||||
|
||||
@ffi.Int()
|
||||
external int contextLength;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ endif()
|
||||
add_library(flutter_libsparkmobile SHARED
|
||||
"flutter_libsparkmobile.cpp"
|
||||
"utils.cpp"
|
||||
"transaction.cpp"
|
||||
)
|
||||
|
||||
add_subdirectory(deps/boost-cmake)
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "deps/sparkmobile/src/spark.h"
|
||||
#include "deps/sparkmobile/bitcoin/uint256.h"
|
||||
#include "structs.h"
|
||||
#include "transaction.h"
|
||||
#include "deps/sparkmobile/bitcoin/script.h" // For CScript.
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream> // Just for printing.
|
||||
@@ -475,4 +477,27 @@ SelectSparkCoinsResult* selectSparkCoins(
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
FFI_PLUGIN_EXPORT
|
||||
SerializedMintContextResult* serializeMintContext(
|
||||
DartInputData* inputs,
|
||||
int inputsLength
|
||||
) {
|
||||
CDataStream serialContextStream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
for (int i = 0; i < inputsLength; i++) {
|
||||
std::vector<unsigned char> vec(inputs[i].txHash, inputs[i].txHash + inputs[i].txHashLength);
|
||||
CTxIn input(
|
||||
uint256(vec),
|
||||
inputs[i].vout,
|
||||
CScript(),
|
||||
std::numeric_limits<unsigned int>::max() - 1);
|
||||
serialContextStream << input;
|
||||
}
|
||||
|
||||
SerializedMintContextResult* result = (SerializedMintContextResult*)malloc(sizeof(SerializedMintContextResult));
|
||||
result->contextLength = serialContextStream.size();
|
||||
result->context = (unsigned char*) malloc(sizeof(unsigned char) * serialContextStream.size());
|
||||
memcpy(result->context, serialContextStream.data(), sizeof(unsigned char) * serialContextStream.size());
|
||||
return result;
|
||||
}
|
||||
@@ -93,4 +93,10 @@ struct SelectSparkCoinsResult* selectSparkCoins(
|
||||
int mintNum
|
||||
);
|
||||
|
||||
FFI_PLUGIN_EXPORT
|
||||
struct SerializedMintContextResult* serializeMintContext(
|
||||
struct DartInputData* inputs,
|
||||
int inputsLength
|
||||
);
|
||||
|
||||
#endif //ORG_FIRO_SPARK_DART_INTERFACE_H
|
||||
|
||||
@@ -220,6 +220,18 @@ struct SparkSpendTransactionResult {
|
||||
int isError;
|
||||
};
|
||||
|
||||
struct DartInputData {
|
||||
unsigned char *txHash;
|
||||
int txHashLength;
|
||||
|
||||
int vout;
|
||||
};
|
||||
|
||||
struct SerializedMintContextResult {
|
||||
unsigned char *context;
|
||||
int contextLength;
|
||||
};
|
||||
|
||||
//#ifdef __cplusplus
|
||||
//}
|
||||
//#endif
|
||||
|
||||
89
src/transaction.cpp
Normal file
89
src/transaction.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2016 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "transaction.h"
|
||||
//#include "script/interpreter.h"
|
||||
#include "deps/sparkmobile/bitcoin/hash.h"
|
||||
#include "deps/sparkmobile/bitcoin/tinyformat.h"
|
||||
#include "deps/sparkmobile/bitcoin/utilstrencodings.h"
|
||||
|
||||
/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/
|
||||
static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000; // 50KB
|
||||
/** Dust Soft Limit, allowed with additional fee per output */
|
||||
static const int64_t DUST_SOFT_LIMIT = 100000; // 0.001 FIRO
|
||||
/** The maximum allowed size for a serialized block, in bytes (network rule) */
|
||||
static const unsigned int MAX_BLOCK_SIZE = 2000000; // 2000KB block hard limit
|
||||
/** Obsolete: maximum size for mined blocks */
|
||||
static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/4; // 500KB block soft limit
|
||||
|
||||
std::string COutPoint::ToString() const
|
||||
{
|
||||
return strprintf("COutPoint(%s, %u)", hash.ToString(), n);
|
||||
}
|
||||
|
||||
std::string COutPoint::ToStringShort() const
|
||||
{
|
||||
return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,64), n);
|
||||
}
|
||||
|
||||
CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn)
|
||||
{
|
||||
prevout = prevoutIn;
|
||||
scriptSig = scriptSigIn;
|
||||
nSequence = nSequenceIn;
|
||||
}
|
||||
|
||||
CTxIn::CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn, uint32_t nSequenceIn)
|
||||
{
|
||||
prevout = COutPoint(hashPrevTx, nOut);
|
||||
scriptSig = scriptSigIn;
|
||||
nSequence = nSequenceIn;
|
||||
}
|
||||
|
||||
bool CTxIn::IsZerocoinSpend() const
|
||||
{
|
||||
return (prevout.IsNull() && scriptSig.size() > 0 && (scriptSig[0] == OP_ZEROCOINSPEND) );
|
||||
}
|
||||
|
||||
bool CTxIn::IsSigmaSpend() const
|
||||
{
|
||||
return (prevout.IsSigmaMintGroup() && scriptSig.size() > 0 && (scriptSig[0] == OP_SIGMASPEND) );
|
||||
}
|
||||
|
||||
bool CTxIn::IsLelantusJoinSplit() const
|
||||
{
|
||||
return (prevout.IsNull() && scriptSig.size() > 0 && (scriptSig[0] == OP_LELANTUSJOINSPLIT || scriptSig[0] == OP_LELANTUSJOINSPLITPAYLOAD) );
|
||||
}
|
||||
|
||||
bool CTxIn::IsZerocoinRemint() const
|
||||
{
|
||||
return (prevout.IsNull() && scriptSig.size() > 0 && (scriptSig[0] == OP_ZEROCOINTOSIGMAREMINT));
|
||||
}
|
||||
|
||||
std::string CTxIn::ToString() const
|
||||
{
|
||||
std::string str;
|
||||
str += "CTxIn(";
|
||||
str += prevout.ToString();
|
||||
if (prevout.IsNull())
|
||||
str += strprintf(", coinbase %s", HexStr(scriptSig).substr(0, 24));
|
||||
else
|
||||
str += strprintf(", scriptSig=%s", HexStr(scriptSig).substr(0, 24));
|
||||
if (nSequence != SEQUENCE_FINAL)
|
||||
str += strprintf(", nSequence=%u", nSequence);
|
||||
str += ")";
|
||||
return str;
|
||||
}
|
||||
|
||||
CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
|
||||
{
|
||||
nValue = nValueIn;
|
||||
scriptPubKey = scriptPubKeyIn;
|
||||
}
|
||||
|
||||
std::string CTxOut::ToString() const
|
||||
{
|
||||
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
|
||||
}
|
||||
270
src/transaction.h
Normal file
270
src/transaction.h
Normal file
@@ -0,0 +1,270 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2016 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_PRIMITIVES_TRANSACTION_H
|
||||
#define BITCOIN_PRIMITIVES_TRANSACTION_H
|
||||
|
||||
#include "deps/sparkmobile/bitcoin/amount.h"
|
||||
#include "deps/sparkmobile/bitcoin/script.h"
|
||||
#include "deps/sparkmobile/bitcoin/serialize.h"
|
||||
#include "deps/sparkmobile/bitcoin/uint256.h"
|
||||
|
||||
#include <exception>
|
||||
|
||||
static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000;
|
||||
|
||||
static const int WITNESS_SCALE_FACTOR = 4;
|
||||
|
||||
class CBadTxIn : public std::exception
|
||||
{
|
||||
};
|
||||
|
||||
class CBadSequence : public CBadTxIn
|
||||
{
|
||||
};
|
||||
|
||||
///** Transaction types */
|
||||
//enum {
|
||||
// TRANSACTION_NORMAL = 0,
|
||||
// TRANSACTION_PROVIDER_REGISTER = 1,
|
||||
// TRANSACTION_PROVIDER_UPDATE_SERVICE = 2,
|
||||
// TRANSACTION_PROVIDER_UPDATE_REGISTRAR = 3,
|
||||
// TRANSACTION_PROVIDER_UPDATE_REVOKE = 4,
|
||||
// TRANSACTION_COINBASE = 5,
|
||||
// TRANSACTION_QUORUM_COMMITMENT = 6,
|
||||
// TRANSACTION_SPORK = 7,
|
||||
// TRANSACTION_LELANTUS = 8,
|
||||
// TRANSACTION_SPARK = 9
|
||||
//};
|
||||
|
||||
/** An outpoint - a combination of a transaction hash and an index n into its vout */
|
||||
class COutPoint
|
||||
{
|
||||
public:
|
||||
uint256 hash;
|
||||
uint32_t n;
|
||||
|
||||
COutPoint() { SetNull(); }
|
||||
COutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; }
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(hash);
|
||||
READWRITE(n);
|
||||
}
|
||||
|
||||
void SetNull() { hash.SetNull(); n = (uint32_t) -1; }
|
||||
bool IsNull() const { return (hash.IsNull() && n == (uint32_t) -1); }
|
||||
|
||||
bool IsSigmaMintGroup() const { return hash.IsNull() && n >= 1; }
|
||||
|
||||
friend bool operator<(const COutPoint& a, const COutPoint& b)
|
||||
{
|
||||
int cmp = a.hash.Compare(b.hash);
|
||||
return cmp < 0 || (cmp == 0 && a.n < b.n);
|
||||
}
|
||||
|
||||
friend bool operator==(const COutPoint& a, const COutPoint& b)
|
||||
{
|
||||
return (a.hash == b.hash && a.n == b.n);
|
||||
}
|
||||
|
||||
friend bool operator!=(const COutPoint& a, const COutPoint& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
std::string ToStringShort() const;
|
||||
};
|
||||
|
||||
/** An input of a transaction. It contains the location of the previous
|
||||
* transaction's output that it claims and a signature that matches the
|
||||
* output's public key.
|
||||
*/
|
||||
class CTxIn
|
||||
{
|
||||
public:
|
||||
COutPoint prevout;
|
||||
CScript scriptSig;
|
||||
uint32_t nSequence;
|
||||
CScript prevPubKey;
|
||||
CScriptWitness scriptWitness; //! Only serialized through CTransaction
|
||||
|
||||
/* Setting nSequence to this value for every input in a transaction
|
||||
* disables nLockTime. */
|
||||
static const uint32_t SEQUENCE_FINAL = 0xffffffff;
|
||||
|
||||
/* Below flags apply in the context of BIP 68*/
|
||||
/* If this flag set, CTxIn::nSequence is NOT interpreted as a
|
||||
* relative lock-time. */
|
||||
static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31);
|
||||
|
||||
/* If CTxIn::nSequence encodes a relative lock-time and this flag
|
||||
* is set, the relative lock-time has units of 512 seconds,
|
||||
* otherwise it specifies blocks with a granularity of 1. */
|
||||
static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22);
|
||||
|
||||
/* If CTxIn::nSequence encodes a relative lock-time, this mask is
|
||||
* applied to extract that lock-time from the sequence field. */
|
||||
static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff;
|
||||
|
||||
/* In order to use the same number of bits to encode roughly the
|
||||
* same wall-clock duration, and because blocks are naturally
|
||||
* limited to occur every 600s on average, the minimum granularity
|
||||
* for time-based relative lock-time is fixed at 512 seconds.
|
||||
* Converting from CTxIn::nSequence to seconds is performed by
|
||||
* multiplying by 512 = 2^9, or equivalently shifting up by
|
||||
* 9 bits. */
|
||||
static const int SEQUENCE_LOCKTIME_GRANULARITY = 9;
|
||||
|
||||
CTxIn()
|
||||
{
|
||||
nSequence = SEQUENCE_FINAL;
|
||||
}
|
||||
|
||||
explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
|
||||
CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(prevout);
|
||||
READWRITE(*(CScriptBase*)(&scriptSig));
|
||||
READWRITE(nSequence);
|
||||
}
|
||||
|
||||
friend bool operator==(const CTxIn& a, const CTxIn& b)
|
||||
{
|
||||
return (a.prevout == b.prevout &&
|
||||
a.scriptSig == b.scriptSig &&
|
||||
a.nSequence == b.nSequence);
|
||||
}
|
||||
|
||||
friend bool operator!=(const CTxIn& a, const CTxIn& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
friend bool operator<(const CTxIn& a, const CTxIn& b)
|
||||
{
|
||||
return a.prevout<b.prevout;
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
bool IsZerocoinSpend() const;
|
||||
bool IsSigmaSpend() const;
|
||||
bool IsLelantusJoinSplit() const;
|
||||
bool IsZerocoinRemint() const;
|
||||
};
|
||||
|
||||
/** An output of a transaction. It contains the public key that the next input
|
||||
* must be able to sign with to claim it.
|
||||
*/
|
||||
class CTxOut
|
||||
{
|
||||
public:
|
||||
CAmount nValue;
|
||||
CScript scriptPubKey;
|
||||
int nRounds;
|
||||
|
||||
CTxOut()
|
||||
{
|
||||
SetNull();
|
||||
}
|
||||
|
||||
CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(nValue);
|
||||
READWRITE(*(CScriptBase*)(&scriptPubKey));
|
||||
if (ser_action.ForRead())
|
||||
nRounds = -10;
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
nValue = -1;
|
||||
scriptPubKey.clear();
|
||||
nRounds = -10; // an initial value, should be no way to get this by calculations
|
||||
}
|
||||
|
||||
bool IsNull() const
|
||||
{
|
||||
return (nValue == -1);
|
||||
}
|
||||
|
||||
CAmount GetDustThreshold(const CFeeRate &minRelayTxFee) const
|
||||
{
|
||||
// "Dust" is defined in terms of CTransaction::minRelayTxFee,
|
||||
// which has units satoshis-per-kilobyte.
|
||||
// If you'd pay more than 1/3 in fees
|
||||
// to spend something, then we consider it dust.
|
||||
// A typical spendable non-segwit txout is 34 bytes big, and will
|
||||
// need a CTxIn of at least 148 bytes to spend:
|
||||
// so dust is a spendable txout less than
|
||||
// 546*minRelayTxFee/1000 (in satoshis).
|
||||
// A typical spendable segwit txout is 31 bytes big, and will
|
||||
// need a CTxIn of at least 67 bytes to spend:
|
||||
// so dust is a spendable txout less than
|
||||
// 294*minRelayTxFee/1000 (in satoshis).
|
||||
if (scriptPubKey.IsUnspendable())
|
||||
return 0;
|
||||
|
||||
size_t nSize = GetSerializeSize(*this, SER_DISK, 0);
|
||||
int witnessversion = 0;
|
||||
std::vector<unsigned char> witnessprogram;
|
||||
|
||||
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
|
||||
// sum the sizes of the parts of a transaction input
|
||||
// with 75% segwit discount applied to the script size.
|
||||
nSize += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4);
|
||||
} else {
|
||||
nSize += (32 + 4 + 1 + 107 + 4); // the 148 mentioned above
|
||||
}
|
||||
|
||||
return 3 * minRelayTxFee.GetFee(nSize);
|
||||
}
|
||||
|
||||
bool IsDust() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsDust(const CFeeRate &minRelayTxFee) const
|
||||
{
|
||||
// return (nValue < GetDustThreshold(minRelayTxFee));
|
||||
//firo: disable dust
|
||||
return false;
|
||||
}
|
||||
|
||||
friend bool operator==(const CTxOut& a, const CTxOut& b)
|
||||
{
|
||||
return (a.nValue == b.nValue &&
|
||||
a.scriptPubKey == b.scriptPubKey);
|
||||
}
|
||||
|
||||
friend bool operator!=(const CTxOut& a, const CTxOut& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
friend bool operator<(const CTxOut& a, const CTxOut& b)
|
||||
{
|
||||
return a.nValue < b.nValue || (a.nValue == b.nValue && a.scriptPubKey < b.scriptPubKey);
|
||||
}
|
||||
|
||||
uint256 GetHash() const { return SerializeHash(*this); }
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_PRIMITIVES_TRANSACTION_H
|
||||
Reference in New Issue
Block a user