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.
cn
Jianping Wu 6 years ago
parent
commit
e23a5a6fe8
  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 @@ @@ -3,10 +3,12 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#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)
: op(OP_NOP), address(script)
@ -85,3 +87,18 @@ CScript CKevaScript::buildKevaNamespace(const CScript& addr, const valtype& name @@ -85,3 +87,18 @@ CScript CKevaScript::buildKevaNamespace(const CScript& addr, const valtype& name
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 @@ @@ -5,6 +5,7 @@
#ifndef H_BITCOIN_SCRIPT_KEVA
#define H_BITCOIN_SCRIPT_KEVA
#include <uint256.h>
#include <script/script.h>
class uint160;
@ -42,7 +43,9 @@ public: @@ -42,7 +43,9 @@ public:
* The key pointing to the internal display name. This is the first
* 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
@ -234,6 +237,9 @@ public: @@ -234,6 +237,9 @@ public:
static CScript buildKevaPut(const CScript& addr, const valtype& nameSpace,
const valtype& key, const valtype& value);
static CScript replaceKevaNamespace(const CScript& oldScript, const uint256& txId, valtype& kaveNamespace);
};
#endif // H_BITCOIN_SCRIPT_KEVA

30
src/wallet/rpckeva.cpp

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

12
src/wallet/rpcwallet.cpp

@ -428,7 +428,8 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA @@ -428,7 +428,8 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA
int nChangePosRet = -1;
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
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)
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError);
@ -441,7 +442,9 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA @@ -441,7 +442,9 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA
}
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,
const CCoinControl& coin_control)
{
@ -478,7 +481,7 @@ void SendMoneyToScript(CWallet* const pwallet, const CScript &scriptPubKey, @@ -478,7 +481,7 @@ void SendMoneyToScript(CWallet* const pwallet, const CScript &scriptPubKey,
int nChangePosRet = -1;
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
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)
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError);
@ -1200,7 +1203,8 @@ UniValue sendmany(const JSONRPCRequest& request) @@ -1200,7 +1203,8 @@ UniValue sendmany(const JSONRPCRequest& request)
CAmount nFeeRequired = 0;
int nChangePosRet = -1;
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)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
CValidationState state;

4
src/wallet/rpcwallet.h

@ -27,7 +27,9 @@ std::string HelpRequiringPassphrase(CWallet *); @@ -27,7 +27,9 @@ std::string HelpRequiringPassphrase(CWallet *);
void EnsureWalletIsUnlocked(CWallet *);
bool EnsureWalletIsAvailable(CWallet *, bool avoidException);
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,
const CCoinControl& coin_control);

3
src/wallet/test/wallet_tests.cpp

@ -636,7 +636,8 @@ public: @@ -636,7 +636,8 @@ public:
int changePos = -1;
std::string error;
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;
BOOST_CHECK(wallet->CommitTransaction(wtx, reservekey, nullptr, state));
CMutableTransaction blocktx;

27
src/wallet/wallet.cpp

@ -2628,7 +2628,8 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC @@ -2628,7 +2628,8 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
CReserveKey reservekey(this);
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;
}
@ -2689,6 +2690,7 @@ OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vec @@ -2689,6 +2690,7 @@ OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vec
bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend,
const CTxIn* withInput,
std::vector<unsigned char>& kaveNamespace,
CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign)
{
@ -2708,8 +2710,9 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, @@ -2708,8 +2710,9 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend,
if (recipient.fSubtractFeeFromAmount)
nSubtractFeeFromAmount++;
if (CKevaScript::isKevaScript (recipient.scriptPubKey))
if (CKevaScript::isKevaScript(recipient.scriptPubKey)) {
isKevacoin = true;
}
}
if (vecSend.empty())
{
@ -2919,9 +2922,21 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, @@ -2919,9 +2922,21 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend,
// and in the spirit of "smallest possible change from prior
// behavior."
const uint32_t nSequence = coin_control.signalRbf ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1);
for (const auto& coin : setCoins)
txNew.vin.push_back(CTxIn(coin.outpoint,CScript(),
nSequence));
bool kevaDummyReplaced = false;
for (const auto& coin : setCoins) {
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.
if (!DummySignTx(txNew, setCoins)) {
@ -3131,11 +3146,9 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon @@ -3131,11 +3146,9 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
{
// Broadcast
if (!wtx.AcceptToMemoryPool(maxTxFee, state)) {
printf("JWU Transaction cannot be broadcast immediately! \n");
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.
} else {
printf("JWU Transaction CAN OK be broadcast immediately! \n");
wtx.RelayWalletTransaction(connman);
}
}

1
src/wallet/wallet.h

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

Loading…
Cancel
Save