mirror of
https://github.com/kvazar-network/kevacoin.git
synced 2025-01-14 09:08:11 +00:00
Finally everything built!
This commit is contained in:
parent
97b35682e0
commit
17a422025e
@ -252,15 +252,13 @@ libbitcoin_wallet_a_SOURCES = \
|
||||
wallet/fees.cpp \
|
||||
wallet/init.cpp \
|
||||
wallet/rpcdump.cpp \
|
||||
wallet/rpckeva.cpp \
|
||||
wallet/rpcwallet.cpp \
|
||||
wallet/wallet.cpp \
|
||||
wallet/walletdb.cpp \
|
||||
wallet/walletutil.cpp \
|
||||
$(BITCOIN_CORE_H)
|
||||
|
||||
libbitcoin_wallet_a_SOURCES += \
|
||||
wallet/rpckeva.cpp
|
||||
|
||||
# crypto primitives library
|
||||
crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(SSL_CFLAGS)
|
||||
crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
@ -328,6 +326,8 @@ libbitcoin_consensus_a_SOURCES = \
|
||||
script/bitcoinconsensus.cpp \
|
||||
script/interpreter.cpp \
|
||||
script/interpreter.h \
|
||||
script/keva.h \
|
||||
script/keva.cpp \
|
||||
script/script.cpp \
|
||||
script/script.h \
|
||||
script/script_error.cpp \
|
||||
@ -338,9 +338,7 @@ libbitcoin_consensus_a_SOURCES = \
|
||||
uint256.h \
|
||||
utilstrencodings.cpp \
|
||||
utilstrencodings.h \
|
||||
version.h \
|
||||
script/keva.h \
|
||||
script/keva.cpp
|
||||
version.h
|
||||
|
||||
# common: shared between bitcoind, and bitcoin-qt and non-server tools
|
||||
libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
|
||||
|
@ -51,7 +51,7 @@ endif
|
||||
|
||||
if ENABLE_WALLET
|
||||
bench_bench_litecoin_SOURCES += bench/coin_selection.cpp
|
||||
bench_bench_litecoin_LDADD += $(LIBBITCOIN_WALLET) $(LIBBITCOIN_CRYPTO)
|
||||
bench_bench_litecoin_LDADD += $(LIBBITCOIN_WALLET) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO)
|
||||
endif
|
||||
|
||||
bench_bench_litecoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
|
||||
|
@ -10,6 +10,7 @@
|
||||
bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
|
||||
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
|
||||
std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint256>(); }
|
||||
bool CCoinsView::HasNamespace(const valtype &nameSpace) const { return false; }
|
||||
bool CCoinsView::GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const { return false; }
|
||||
bool CCoinsView::GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const { return false; }
|
||||
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
|
||||
@ -27,6 +28,7 @@ bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { re
|
||||
bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->HaveCoin(outpoint); }
|
||||
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
|
||||
std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); }
|
||||
bool CCoinsViewBacked::HasNamespace(const valtype &nameSpace) const { return false; }
|
||||
bool CCoinsViewBacked::GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const { return false; }
|
||||
bool CCoinsViewBacked::GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const { return false; }
|
||||
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
|
||||
@ -148,6 +150,10 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
|
||||
hashBlock = hashBlockIn;
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::HasNamespace(const valtype &nameSpace) const {
|
||||
return cacheNames.hasNamespace(nameSpace);
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const {
|
||||
if (cacheNames.isDeleted(nameSpace, key))
|
||||
return false;
|
||||
@ -160,7 +166,6 @@ bool CCoinsViewCache::GetName(const valtype &nameSpace, const valtype &key, CKev
|
||||
return base->GetName(nameSpace, key, data);
|
||||
}
|
||||
|
||||
|
||||
bool CCoinsViewCache::GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const {
|
||||
/* Query the base view first, and then apply the cached changes (if
|
||||
there are any). */
|
||||
|
@ -164,6 +164,9 @@ public:
|
||||
//! the old block hash, in that order.
|
||||
virtual std::vector<uint256> GetHeadBlocks() const;
|
||||
|
||||
// Check if a namespace exists.
|
||||
virtual bool HasNamespace(const valtype& nameSpace) const;
|
||||
|
||||
// Get a name (if it exists)
|
||||
virtual bool GetName(const valtype& nameSpace, const valtype& key, CKevaData& data) const;
|
||||
|
||||
@ -200,6 +203,7 @@ public:
|
||||
bool HaveCoin(const COutPoint &outpoint) const override;
|
||||
uint256 GetBestBlock() const override;
|
||||
std::vector<uint256> GetHeadBlocks() const override;
|
||||
bool HasNamespace(const valtype& nameSpace) const override;
|
||||
bool GetName(const valtype& nameSpace, const valtype& key, CKevaData& data) const override;
|
||||
bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override;
|
||||
void SetBackend(CCoinsView &viewIn);
|
||||
@ -240,6 +244,7 @@ public:
|
||||
bool HaveCoin(const COutPoint &outpoint) const override;
|
||||
uint256 GetBestBlock() const override;
|
||||
void SetBestBlock(const uint256 &hashBlock);
|
||||
bool HasNamespace(const valtype &nameSpace) const override;
|
||||
bool GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const override;
|
||||
bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override;
|
||||
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
|
||||
|
@ -174,7 +174,7 @@ CCacheNameIterator::next (valtype& name, CKevaData& data)
|
||||
/* CKevaCache. */
|
||||
|
||||
bool
|
||||
CKevaCache::get (const valtype& nameSpace, const valtype& key, CKevaData& data) const
|
||||
CKevaCache::get(const valtype& nameSpace, const valtype& key, CKevaData& data) const
|
||||
{
|
||||
valtype name = nameSpace;
|
||||
name.insert( name.end(), key.begin(), key.end() );
|
||||
@ -186,8 +186,14 @@ CKevaCache::get (const valtype& nameSpace, const valtype& key, CKevaData& data)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKevaCache::hasNamespace(const valtype& nameSpace) const
|
||||
{
|
||||
auto ni = namespaces.find(nameSpace);
|
||||
return (ni != namespaces.end());
|
||||
}
|
||||
|
||||
void
|
||||
CKevaCache::set (const valtype& nameSpace, const valtype& key, const CKevaData& data)
|
||||
CKevaCache::set(const valtype& nameSpace, const valtype& key, const CKevaData& data)
|
||||
{
|
||||
valtype name = nameSpace;
|
||||
name.insert( name.end(), key.begin(), key.end() );
|
||||
@ -200,10 +206,12 @@ CKevaCache::set (const valtype& nameSpace, const valtype& key, const CKevaData&
|
||||
ei->second = data;
|
||||
else
|
||||
entries.insert (std::make_pair (name, data));
|
||||
|
||||
namespaces.insert(nameSpace);
|
||||
}
|
||||
|
||||
void
|
||||
CKevaCache::remove (const valtype& nameSpace, const valtype& key)
|
||||
CKevaCache::remove(const valtype& nameSpace, const valtype& key)
|
||||
{
|
||||
valtype name = nameSpace;
|
||||
name.insert( name.end(), key.begin(), key.end() );
|
||||
@ -215,7 +223,7 @@ CKevaCache::remove (const valtype& nameSpace, const valtype& key)
|
||||
}
|
||||
|
||||
CNameIterator*
|
||||
CKevaCache::iterateNames (CNameIterator* base) const
|
||||
CKevaCache::iterateNames(CNameIterator* base) const
|
||||
{
|
||||
return new CCacheNameIterator (*this, base);
|
||||
}
|
||||
|
@ -377,6 +377,7 @@ public:
|
||||
* by the unit tests.
|
||||
*/
|
||||
typedef std::map<valtype, CKevaData, NameComparator> EntryMap;
|
||||
typedef std::set<valtype> NamespaceSet;
|
||||
|
||||
private:
|
||||
|
||||
@ -384,6 +385,8 @@ private:
|
||||
EntryMap entries;
|
||||
/** Deleted names. */
|
||||
std::set<valtype> deleted;
|
||||
/** Namespaces */
|
||||
NamespaceSet namespaces;
|
||||
|
||||
#if 0
|
||||
/**
|
||||
@ -448,14 +451,16 @@ public:
|
||||
|
||||
/* Try to get a name's associated data. This looks only
|
||||
in entries, and doesn't care about deleted data. */
|
||||
bool get (const valtype& nameSpace, const valtype& key, CKevaData& data) const;
|
||||
bool get(const valtype& nameSpace, const valtype& key, CKevaData& data) const;
|
||||
|
||||
bool hasNamespace(const valtype& nameSpace) const;
|
||||
|
||||
/* Insert (or update) a name. If it is marked as "deleted", this also
|
||||
removes the "deleted" mark. */
|
||||
void set (const valtype& nameSpace, const valtype& key, const CKevaData& data);
|
||||
void set(const valtype& nameSpace, const valtype& key, const CKevaData& data);
|
||||
|
||||
/* Delete a name. If it is in the "entries" set also, remove it there. */
|
||||
void remove (const valtype& nameSpace, const valtype& key);
|
||||
void remove(const valtype& nameSpace, const valtype& key);
|
||||
|
||||
/* Return a name iterator that combines a "base" iterator with the changes
|
||||
made to it according to the cache. The base iterator is taken
|
||||
|
@ -284,7 +284,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
|
||||
// should be a bit faster.
|
||||
// However, if we happen to be in the middle of processing a reorg, then
|
||||
// the mempool can be in an inconsistent state. In this case, the set
|
||||
// of ancestors reachable via mapLinks will be the same as the set of
|
||||
// of ancestors reachable via mapLinks will be the same as the set of
|
||||
// ancestors whose packages include this transaction, because when we
|
||||
// add a new transaction to the mempool in addUnchecked(), we assume it
|
||||
// has no children, and in the case of a reorg where that assumption is
|
||||
@ -329,7 +329,7 @@ void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee,
|
||||
}
|
||||
|
||||
CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator) :
|
||||
nTransactionsUpdated(0), minerPolicyEstimator(estimator)
|
||||
nTransactionsUpdated(0), minerPolicyEstimator(estimator), kevaMemPool(*this)
|
||||
{
|
||||
_clear(); //lock free clear
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <amount.h>
|
||||
#include <coins.h>
|
||||
#include <indirectmap.h>
|
||||
#include <keva/main.h>
|
||||
#include <policy/feerate.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <sync.h>
|
||||
@ -472,6 +473,9 @@ private:
|
||||
mutable bool blockSinceLastRollingFeeBump;
|
||||
mutable double rollingMinimumFeeRate; //!< minimum fee to get into the pool, decreases exponentially
|
||||
|
||||
/** Keva-related mempool data. */
|
||||
CKevaMemPool kevaMemPool;
|
||||
|
||||
void trackPackageRemoved(const CFeeRate& rate);
|
||||
|
||||
public:
|
||||
@ -661,6 +665,38 @@ public:
|
||||
return (mapTx.count(hash) != 0);
|
||||
}
|
||||
|
||||
inline bool registersNamespace(const valtype& nameSpace) const
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
return kevaMemPool.registersNamespace(nameSpace);
|
||||
}
|
||||
|
||||
inline bool updatesKey(const valtype& nameSpace, const valtype& key) const
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
return kevaMemPool.updatesKey(nameSpace, key);
|
||||
}
|
||||
|
||||
inline uint256 getTxForNamespace(const valtype& name) const
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
return kevaMemPool.getTxForNamespace(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a tx can be added to it according to name criteria.
|
||||
* (The non-name criteria are checked in main.cpp and not here, we
|
||||
* leave it there for as little changes as possible.)
|
||||
* @param tx The tx that should be added.
|
||||
* @return True if it doesn't conflict.
|
||||
*/
|
||||
inline bool
|
||||
checkNameOps (const CTransaction& tx) const
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
return kevaMemPool.checkTx(tx);
|
||||
}
|
||||
|
||||
CTransactionRef get(const uint256& hash) const;
|
||||
TxMempoolInfo info(const uint256& hash) const;
|
||||
std::vector<TxMempoolInfo> infoAll() const;
|
||||
|
@ -24,8 +24,7 @@
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
UniValue
|
||||
keva_namespace (const JSONRPCRequest& request)
|
||||
UniValue keva_namespace(const JSONRPCRequest& request)
|
||||
{
|
||||
CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!EnsureWalletIsAvailable (pwallet, request.fHelp))
|
||||
@ -50,9 +49,9 @@ keva_namespace (const JSONRPCRequest& request)
|
||||
|
||||
ObserveSafeMode ();
|
||||
|
||||
const std::string displayNameStr = request.params[0].get_str ();
|
||||
const std::string displayNameStr = request.params[0].get_str();
|
||||
const valtype displayName = ValtypeFromString (displayNameStr);
|
||||
if (displayName.size () > MAX_NAME_LENGTH)
|
||||
if (displayName.size () > MAX_NAMESPACE_LENGTH)
|
||||
throw JSONRPCError (RPC_INVALID_PARAMETER, "the name is too long");
|
||||
|
||||
/* No explicit locking should be necessary. CReserveKey takes care
|
||||
@ -66,7 +65,7 @@ keva_namespace (const JSONRPCRequest& request)
|
||||
const bool ok = keyName.GetReservedKey(pubKey, true);
|
||||
assert (ok);
|
||||
|
||||
CKeyID keyId = pubKey.GetID()
|
||||
CKeyID keyId = pubKey.GetID();
|
||||
|
||||
// The namespace is: Hash160(Hash160(keyId) || displayName)
|
||||
valtype toHash = ToByteVector(Hash160(ToByteVector(keyId)));
|
||||
@ -79,24 +78,23 @@ keva_namespace (const JSONRPCRequest& request)
|
||||
CCoinControl coinControl;
|
||||
CWalletTx wtx;
|
||||
SendMoneyToScript(pwallet, newScript, nullptr,
|
||||
NAME_LOCKED_AMOUNT, false, wtx, coinControl);
|
||||
KEVA_LOCKED_AMOUNT, false, wtx, coinControl);
|
||||
|
||||
keyName.KeepKey();
|
||||
|
||||
const std::string randStr = HexStr(rand);
|
||||
const std::string txid = wtx.GetHash().GetHex();
|
||||
LogPrintf ("name_new: name=%s, rand=%s, tx=%s\n",
|
||||
nameStr.c_str(), randStr.c_str(), txid.c_str());
|
||||
LogPrintf("keva_namespace: namespace=%s, displayName=%s, tx=%s\n",
|
||||
namespaceHash.ToString().c_str(), displayNameStr.c_str(), txid.c_str());
|
||||
|
||||
UniValue res(UniValue::VARR);
|
||||
res.push_back(txid);
|
||||
res.push_back(randStr);
|
||||
res.push_back(namespaceHash.ToString());
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
#if 0
|
||||
UniValue keva_namespace(const JSONRPCRequest& request)
|
||||
{
|
||||
CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
@ -123,20 +121,22 @@ UniValue keva_namespace(const JSONRPCRequest& request)
|
||||
|
||||
ObserveSafeMode ();
|
||||
|
||||
const std::string displayName = request.params[0].get_str();
|
||||
const valtype displayNameVal = ValtypeFromString(displayName);
|
||||
if (displayNameVal.size() > MAX_NAMESPACE_LENGTH)
|
||||
const valtype displayName = ValtypeFromString(request.params[0].get_str());
|
||||
if (displayName.size() > MAX_NAMESPACE_LENGTH) {
|
||||
throw JSONRPCError (RPC_INVALID_PARAMETER, "the display name of the namespace is too long");
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Reject updates to a name for which the mempool already has
|
||||
a pending update. This is not a hard rule enforced by network
|
||||
rules, but it is necessary with the current mempool implementation. */
|
||||
{
|
||||
LOCK (mempool.cs);
|
||||
if (mempool.updatesName(name))
|
||||
if (mempool.registersNamespace(name))
|
||||
throw JSONRPCError (RPC_TRANSACTION_ERROR,
|
||||
"there is already a pending update for this name");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* No more locking required, similarly to name_new. */
|
||||
EnsureWalletIsUnlocked (pwallet);
|
||||
@ -148,36 +148,31 @@ UniValue keva_namespace(const JSONRPCRequest& request)
|
||||
bool usedKey = false;
|
||||
|
||||
CScript addrName;
|
||||
if (request.params.size () == 3)
|
||||
{
|
||||
keyName.ReturnKey ();
|
||||
const CTxDestination dest
|
||||
= DecodeDestination (request.params[2].get_str ());
|
||||
if (!IsValidDestination (dest))
|
||||
throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, "invalid address");
|
||||
|
||||
addrName = GetScriptForDestination (dest);
|
||||
}
|
||||
else
|
||||
{
|
||||
usedKey = true;
|
||||
addrName = GetScriptForDestination (pubKeyReserve.GetID ());
|
||||
if (request.params.size () == 3) {
|
||||
keyName.ReturnKey();
|
||||
const CTxDestination dest = DecodeDestination (request.params[2].get_str ());
|
||||
if (!IsValidDestination (dest)) {
|
||||
throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, "invalid address");
|
||||
}
|
||||
addrName = GetScriptForDestination(dest);
|
||||
} else {
|
||||
usedKey = true;
|
||||
addrName = GetScriptForDestination(pubKeyReserve.GetID ());
|
||||
}
|
||||
|
||||
const CScript nameScript
|
||||
= CNameScript::buildNameUpdate (addrName, name, value);
|
||||
const CScript kevaScript = CKevaScript::buildKevaNamespace(addrName, name, displayName);
|
||||
|
||||
CCoinControl coinControl;
|
||||
CWalletTx wtx;
|
||||
SendMoneyToScript (pwallet, nameScript, &txIn,
|
||||
NAME_LOCKED_AMOUNT, false, wtx, coinControl);
|
||||
SendMoneyToScript(pwallet, kevaScript, nullptr, KEVA_LOCKED_AMOUNT, false, wtx, coinControl);
|
||||
|
||||
if (usedKey)
|
||||
if (usedKey) {
|
||||
keyName.KeepKey ();
|
||||
}
|
||||
|
||||
return wtx.GetHash ().GetHex ();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
UniValue keva_put(const JSONRPCRequest& request)
|
||||
{
|
||||
@ -207,8 +202,8 @@ UniValue keva_put(const JSONRPCRequest& request)
|
||||
ObserveSafeMode ();
|
||||
|
||||
const std::string namespaceStr = request.params[0].get_str ();
|
||||
const valtype namespaceVal = ValtypeFromString (namespaceStr);
|
||||
if (namespaceVal.size () > MAX_NAMESPACE_LENGTH)
|
||||
const valtype nameSpace = ValtypeFromString (namespaceStr);
|
||||
if (nameSpace.size () > MAX_NAMESPACE_LENGTH)
|
||||
throw JSONRPCError (RPC_INVALID_PARAMETER, "the namespace is too long");
|
||||
|
||||
const std::string keyStr = request.params[1].get_str ();
|
||||
@ -231,17 +226,19 @@ UniValue keva_put(const JSONRPCRequest& request)
|
||||
rules, but it is necessary with the current mempool implementation. */
|
||||
{
|
||||
LOCK (mempool.cs);
|
||||
if (mempool.updatesName (name))
|
||||
if (mempool.updatesKey(nameSpace, key)) {
|
||||
throw JSONRPCError (RPC_TRANSACTION_ERROR,
|
||||
"there is already a pending update for this name");
|
||||
}
|
||||
}
|
||||
|
||||
CNameData oldData;
|
||||
CKevaData oldData;
|
||||
{
|
||||
LOCK (cs_main);
|
||||
if (!pcoinsTip->GetName (name, oldData) || oldData.isExpired ())
|
||||
if (!pcoinsTip->HasNamespace(nameSpace)) {
|
||||
throw JSONRPCError (RPC_TRANSACTION_ERROR,
|
||||
"this name can not be updated");
|
||||
"this name can not be updated");
|
||||
}
|
||||
}
|
||||
|
||||
const COutPoint outp = oldData.getUpdateOutpoint ();
|
||||
@ -275,12 +272,12 @@ UniValue keva_put(const JSONRPCRequest& request)
|
||||
}
|
||||
|
||||
const CScript nameScript
|
||||
= CNameScript::buildNameUpdate (addrName, name, value);
|
||||
= CKevaScript::buildKevaPut(addrName, nameSpace, key, value);
|
||||
|
||||
CCoinControl coinControl;
|
||||
CWalletTx wtx;
|
||||
SendMoneyToScript (pwallet, nameScript, &txIn,
|
||||
NAME_LOCKED_AMOUNT, false, wtx, coinControl);
|
||||
SendMoneyToScript(pwallet, nameScript, &txIn,
|
||||
KEVA_LOCKED_AMOUNT, false, wtx, coinControl);
|
||||
|
||||
if (usedKey)
|
||||
keyName.KeepKey ();
|
||||
|
@ -636,7 +636,7 @@ public:
|
||||
int changePos = -1;
|
||||
std::string error;
|
||||
CCoinControl dummy;
|
||||
BOOST_CHECK(wallet->CreateTransaction({recipient}, wtx, reservekey, fee, changePos, error, dummy));
|
||||
BOOST_CHECK(wallet->CreateTransaction({recipient}, nullptr, wtx, reservekey, fee, changePos, error, dummy));
|
||||
CValidationState state;
|
||||
BOOST_CHECK(wallet->CommitTransaction(wtx, reservekey, nullptr, state));
|
||||
CMutableTransaction blocktx;
|
||||
|
Loading…
Reference in New Issue
Block a user