Browse Source

Used hash of the first TxIn as namespace id. This ensures that the namespace id is unqiue.

TODO: verify that the TxIn is indeed the hash of the first TxIn.
0.16.3-insta
Jianping Wu 6 years ago
parent
commit
019de6dc09
  1. 21
      src/script/keva.cpp
  2. 8
      src/script/keva.h
  3. 30
      src/wallet/rpckeva.cpp
  4. 12
      src/wallet/rpcwallet.cpp
  5. 4
      src/wallet/rpcwallet.h
  6. 3
      src/wallet/test/wallet_tests.cpp
  7. 27
      src/wallet/wallet.cpp
  8. 1
      src/wallet/wallet.h

21
src/script/keva.cpp

@ -3,10 +3,12 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <script/keva.h> #include <script/keva.h>
#include <hash.h>
#include "base58.h"
#include <uint256.h> const std::string CKevaScript::KEVA_DISPLAY_NAME_KEY = "_KEVA_NS_";
std::string CKevaScript::KEVA_DISPLAY_NAME_KEY = "_KEVA_NS_"; const unsigned char CKevaScript::NAMESPACE_PREFIX = 21; // 2 in base58
CKevaScript::CKevaScript (const CScript& script) CKevaScript::CKevaScript (const CScript& script)
: op(OP_NOP), address(script) : op(OP_NOP), address(script)
@ -85,3 +87,18 @@ CScript CKevaScript::buildKevaNamespace(const CScript& addr, const valtype& name
return prefix + addr; return prefix + addr;
} }
CScript CKevaScript::replaceKevaNamespace(const CScript& oldScript, const uint256& txId, valtype& kaveNamespace)
{
CKevaScript kevaOp(oldScript);
if (!kevaOp.isNamespaceRegistration()) {
assert (false);
return CScript();
}
const valtype& displayName = kevaOp.getOpNamespaceDisplayName();
kaveNamespace = ToByteVector(Hash160(ToByteVector(txId)));
kaveNamespace.insert(kaveNamespace.begin(), NAMESPACE_PREFIX);
//kaveNamespace = EncodeBase58(kaveNamespaceVal);
return CKevaScript::buildKevaNamespace(kevaOp.getAddress(), kaveNamespace, displayName);
}

8
src/script/keva.h

@ -5,6 +5,7 @@
#ifndef H_BITCOIN_SCRIPT_KEVA #ifndef H_BITCOIN_SCRIPT_KEVA
#define H_BITCOIN_SCRIPT_KEVA #define H_BITCOIN_SCRIPT_KEVA
#include <uint256.h>
#include <script/script.h> #include <script/script.h>
class uint160; class uint160;
@ -42,7 +43,9 @@ public:
* The key pointing to the internal display name. This is the first * The key pointing to the internal display name. This is the first
* key created when a namespace is registered. * key created when a namespace is registered.
*/ */
static std::string KEVA_DISPLAY_NAME_KEY; static const std::string KEVA_DISPLAY_NAME_KEY;
static const unsigned char NAMESPACE_PREFIX;
/** /**
* Parse a script and determine whether it is a valid name script. Sets * Parse a script and determine whether it is a valid name script. Sets
@ -234,6 +237,9 @@ public:
static CScript buildKevaPut(const CScript& addr, const valtype& nameSpace, static CScript buildKevaPut(const CScript& addr, const valtype& nameSpace,
const valtype& key, const valtype& value); const valtype& key, const valtype& value);
static CScript replaceKevaNamespace(const CScript& oldScript, const uint256& txId, valtype& kaveNamespace);
}; };
#endif // H_BITCOIN_SCRIPT_KEVA #endif // H_BITCOIN_SCRIPT_KEVA

30
src/wallet/rpckeva.cpp

@ -21,7 +21,8 @@
#include <univalue.h> #include <univalue.h>
const unsigned char NAMESPACE_PREFIX = 21; // 2 in base58 const int NAMESPACE_LENGTH = 21;
const std::string DUMMY_NAMESPACE = "___DUMMY_NAMESPACE___";
/* ************************************************************************** */ /* ************************************************************************** */
@ -71,34 +72,32 @@ UniValue keva_namespace(const JSONRPCRequest& request)
CKeyID keyId = pubKey.GetID(); CKeyID keyId = pubKey.GetID();
// The namespace name is: Hash160(Hash160(keyId) || displayName) // The namespace name is: Hash160("first txin" || displayName)
// JWU TODO: double check this! How can node verify this!!!??? // For now we don't know the first txin, so use dummy name here.
valtype toHash = ToByteVector(Hash160(ToByteVector(keyId))); // It will be replaced later in CreateTransaction.
toHash.insert(toHash.end(), displayName.begin(), displayName.end()); valtype namespaceDummy = ToByteVector(std::string(DUMMY_NAMESPACE));
valtype namespaceHashVal = ToByteVector(Hash160(toHash)); assert(namespaceDummy.size() == NAMESPACE_LENGTH);
namespaceHashVal.insert(namespaceHashVal.begin(), NAMESPACE_PREFIX);
const std::string namespaceHash = EncodeBase58(namespaceHashVal);
//const CScript addrName = GetScriptForDestination(keyId);
CScript redeemScript = GetScriptForDestination(WitnessV0KeyHash(keyId)); CScript redeemScript = GetScriptForDestination(WitnessV0KeyHash(keyId));
CScriptID scriptHash = CScriptID(redeemScript); CScriptID scriptHash = CScriptID(redeemScript);
CScript addrName = GetScriptForDestination(scriptHash); CScript addrName = GetScriptForDestination(scriptHash);
const CScript newScript = CKevaScript::buildKevaNamespace(addrName, namespaceHashVal, displayName); const CScript newScript = CKevaScript::buildKevaNamespace(addrName, namespaceDummy, displayName);
CCoinControl coinControl; CCoinControl coinControl;
CWalletTx wtx; CWalletTx wtx;
SendMoneyToScript(pwallet, newScript, nullptr, valtype kevaNamespace;
SendMoneyToScript(pwallet, newScript, nullptr, kevaNamespace,
KEVA_LOCKED_AMOUNT, false, wtx, coinControl); KEVA_LOCKED_AMOUNT, false, wtx, coinControl);
keyName.KeepKey(); keyName.KeepKey();
std::string kevaNamespaceBase58 = EncodeBase58(kevaNamespace);
const std::string txid = wtx.GetHash().GetHex(); const std::string txid = wtx.GetHash().GetHex();
LogPrintf("keva_namespace: namespace=%s, displayName=%s, tx=%s\n", LogPrintf("keva_namespace: namespace=%s, displayName=%s, tx=%s\n",
namespaceHash.c_str(), displayNameStr.c_str(), txid.c_str()); kevaNamespaceBase58.c_str(), displayNameStr.c_str(), txid.c_str());
UniValue res(UniValue::VARR); UniValue res(UniValue::VARR);
res.push_back(txid); res.push_back(txid);
res.push_back(namespaceHash); res.push_back(kevaNamespaceBase58);
return res; return res;
} }
@ -275,7 +274,8 @@ UniValue keva_put(const JSONRPCRequest& request)
CCoinControl coinControl; CCoinControl coinControl;
CWalletTx wtx; CWalletTx wtx;
SendMoneyToScript(pwallet, kevaScript, &txIn, valtype empty;
SendMoneyToScript(pwallet, kevaScript, &txIn, empty,
KEVA_LOCKED_AMOUNT, false, wtx, coinControl); KEVA_LOCKED_AMOUNT, false, wtx, coinControl);
if (usedKey) { if (usedKey) {

12
src/wallet/rpcwallet.cpp

@ -428,7 +428,8 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA
int nChangePosRet = -1; int nChangePosRet = -1;
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount}; CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
vecSend.push_back(recipient); vecSend.push_back(recipient);
if (!pwallet->CreateTransaction(vecSend, nullptr, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) { std::vector<unsigned char> empty;
if (!pwallet->CreateTransaction(vecSend, nullptr, empty, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) {
if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance) if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired)); strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError); throw JSONRPCError(RPC_WALLET_ERROR, strError);
@ -441,7 +442,9 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA
} }
void SendMoneyToScript(CWallet* const pwallet, const CScript &scriptPubKey, void SendMoneyToScript(CWallet* const pwallet, const CScript &scriptPubKey,
const CTxIn* withInput, CAmount nValue, const CTxIn* withInput,
std::vector<unsigned char>& kevaNamespace,
CAmount nValue,
bool fSubtractFeeFromAmount, CWalletTx& wtxNew, bool fSubtractFeeFromAmount, CWalletTx& wtxNew,
const CCoinControl& coin_control) const CCoinControl& coin_control)
{ {
@ -478,7 +481,7 @@ void SendMoneyToScript(CWallet* const pwallet, const CScript &scriptPubKey,
int nChangePosRet = -1; int nChangePosRet = -1;
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount}; CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
vecSend.push_back(recipient); vecSend.push_back(recipient);
if (!pwallet->CreateTransaction(vecSend, withInput, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) { if (!pwallet->CreateTransaction(vecSend, withInput, kevaNamespace, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) {
if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance) if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired)); strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError); throw JSONRPCError(RPC_WALLET_ERROR, strError);
@ -1200,7 +1203,8 @@ UniValue sendmany(const JSONRPCRequest& request)
CAmount nFeeRequired = 0; CAmount nFeeRequired = 0;
int nChangePosRet = -1; int nChangePosRet = -1;
std::string strFailReason; std::string strFailReason;
bool fCreated = pwallet->CreateTransaction(vecSend, nullptr, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control); std::vector<unsigned char> empty; empty;
bool fCreated = pwallet->CreateTransaction(vecSend, nullptr, empty, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control);
if (!fCreated) if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
CValidationState state; CValidationState state;

4
src/wallet/rpcwallet.h

@ -27,7 +27,9 @@ std::string HelpRequiringPassphrase(CWallet *);
void EnsureWalletIsUnlocked(CWallet *); void EnsureWalletIsUnlocked(CWallet *);
bool EnsureWalletIsAvailable(CWallet *, bool avoidException); bool EnsureWalletIsAvailable(CWallet *, bool avoidException);
void SendMoneyToScript(CWallet* pwallet, const CScript& scriptPubKey, void SendMoneyToScript(CWallet* pwallet, const CScript& scriptPubKey,
const CTxIn* withInput, CAmount nValue, const CTxIn* withInput,
std::vector<unsigned char>& kevaNamespace,
CAmount nValue,
bool fSubtractFeeFromAmount, CWalletTx& wtxNew, bool fSubtractFeeFromAmount, CWalletTx& wtxNew,
const CCoinControl& coin_control); const CCoinControl& coin_control);

3
src/wallet/test/wallet_tests.cpp

@ -636,7 +636,8 @@ public:
int changePos = -1; int changePos = -1;
std::string error; std::string error;
CCoinControl dummy; CCoinControl dummy;
BOOST_CHECK(wallet->CreateTransaction({recipient}, nullptr, wtx, reservekey, fee, changePos, error, dummy)); std::vector<unsigned char> empty;
BOOST_CHECK(wallet->CreateTransaction({recipient}, nullptr, empty, wtx, reservekey, fee, changePos, error, dummy));
CValidationState state; CValidationState state;
BOOST_CHECK(wallet->CommitTransaction(wtx, reservekey, nullptr, state)); BOOST_CHECK(wallet->CommitTransaction(wtx, reservekey, nullptr, state));
CMutableTransaction blocktx; CMutableTransaction blocktx;

27
src/wallet/wallet.cpp

@ -2628,7 +2628,8 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
CReserveKey reservekey(this); CReserveKey reservekey(this);
CWalletTx wtx; CWalletTx wtx;
if (!CreateTransaction(vecSend, nullptr, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) { std::vector<unsigned char> empty;
if (!CreateTransaction(vecSend, nullptr, empty, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) {
return false; return false;
} }
@ -2689,6 +2690,7 @@ OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vec
bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend,
const CTxIn* withInput, const CTxIn* withInput,
std::vector<unsigned char>& kaveNamespace,
CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign) int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign)
{ {
@ -2708,9 +2710,10 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend,
if (recipient.fSubtractFeeFromAmount) if (recipient.fSubtractFeeFromAmount)
nSubtractFeeFromAmount++; nSubtractFeeFromAmount++;
if (CKevaScript::isKevaScript (recipient.scriptPubKey)) if (CKevaScript::isKevaScript(recipient.scriptPubKey)) {
isKevacoin = true; isKevacoin = true;
} }
}
if (vecSend.empty()) if (vecSend.empty())
{ {
strFailReason = _("Transaction must have at least one recipient"); strFailReason = _("Transaction must have at least one recipient");
@ -2919,9 +2922,21 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend,
// and in the spirit of "smallest possible change from prior // and in the spirit of "smallest possible change from prior
// behavior." // behavior."
const uint32_t nSequence = coin_control.signalRbf ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1); const uint32_t nSequence = coin_control.signalRbf ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1);
for (const auto& coin : setCoins) bool kevaDummyReplaced = false;
txNew.vin.push_back(CTxIn(coin.outpoint,CScript(), for (const auto& coin : setCoins) {
nSequence)); txNew.vin.push_back(CTxIn(coin.outpoint,CScript(), nSequence));
if (isKevacoin && !kevaDummyReplaced) {
for (std::vector<CTxOut>::iterator iter = txNew.vout.begin(); iter != txNew.vout.end(); ++iter) {
CScript dummyScript = iter->scriptPubKey;
CKevaScript kevaOp(dummyScript);
if (kevaOp.isKevaOp() && kevaOp.isNamespaceRegistration()) {
iter->scriptPubKey = CKevaScript::replaceKevaNamespace(dummyScript, coin.outpoint.hash, kaveNamespace);
kevaDummyReplaced = true;
break;
}
}
}
}
// Fill in dummy signatures for fee calculation. // Fill in dummy signatures for fee calculation.
if (!DummySignTx(txNew, setCoins)) { if (!DummySignTx(txNew, setCoins)) {
@ -3131,11 +3146,9 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
{ {
// Broadcast // Broadcast
if (!wtx.AcceptToMemoryPool(maxTxFee, state)) { if (!wtx.AcceptToMemoryPool(maxTxFee, state)) {
printf("JWU Transaction cannot be broadcast immediately! \n");
LogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", state.GetRejectReason()); LogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", state.GetRejectReason());
// TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure. // TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
} else { } else {
printf("JWU Transaction CAN OK be broadcast immediately! \n");
wtx.RelayWalletTransaction(connman); wtx.RelayWalletTransaction(connman);
} }
} }

1
src/wallet/wallet.h

@ -993,6 +993,7 @@ public:
*/ */
bool CreateTransaction(const std::vector<CRecipient>& vecSend, bool CreateTransaction(const std::vector<CRecipient>& vecSend,
const CTxIn* withInput, const CTxIn* withInput,
std::vector<unsigned char>& kaveNamespace,
CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut,
std::string& strFailReason, const CCoinControl& coin_control, bool sign = true); std::string& strFailReason, const CCoinControl& coin_control, bool sign = true);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state);

Loading…
Cancel
Save