mirror of
https://github.com/kvazar-network/kevacoin.git
synced 2025-01-27 07:14:48 +00:00
WIP: implemented keva_delete.
Problem: after the call, the corresponding keva coin is gone!
This commit is contained in:
parent
ceefe25a87
commit
df20cfc6d2
@ -22,7 +22,9 @@ CKevaData::fromScript (unsigned h, const COutPoint& out,
|
||||
const CKevaScript& script)
|
||||
{
|
||||
if (script.isAnyUpdate()) {
|
||||
value = script.getOpValue();
|
||||
if (!script.isDelete()) {
|
||||
value = script.getOpValue();
|
||||
}
|
||||
} else if (script.isNamespaceRegistration()) {
|
||||
value = script.getOpNamespaceDisplayName();
|
||||
} else {
|
||||
@ -212,14 +214,14 @@ CKevaCache::set(const valtype& nameSpace, const valtype& key, const CKevaData& d
|
||||
auto name = std::make_tuple(nameSpace, key);
|
||||
const std::set<NamespaceKeyType>::iterator di = deleted.find(name);
|
||||
if (di != deleted.end()) {
|
||||
deleted.erase (di);
|
||||
deleted.erase(di);
|
||||
}
|
||||
|
||||
const EntryMap::iterator ei = entries.find(name);
|
||||
if (ei != entries.end ())
|
||||
if (ei != entries.end())
|
||||
ei->second = data;
|
||||
else
|
||||
entries.insert (std::make_pair(name, data));
|
||||
entries.insert(std::make_pair(name, data));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -58,6 +58,12 @@ CKevaMemPool::addUnchecked (const uint256& hash, const CTxMemPoolEntry& entry)
|
||||
const valtype& nameSpace = entry.getNamespace();
|
||||
listUnconfirmedKeyValues.push_back(std::make_tuple(hash, nameSpace, entry.getKey(), entry.getValue()));
|
||||
}
|
||||
|
||||
if (entry.isKeyDelete()) {
|
||||
const valtype& nameSpace = entry.getNamespace();
|
||||
const valtype& empty = ValtypeFromString("");
|
||||
listUnconfirmedKeyValues.push_back(std::make_tuple(hash, nameSpace, entry.getKey(), empty));
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@ -113,7 +119,7 @@ void CKevaMemPool::remove(const CTxMemPoolEntry& entry)
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.isKeyUpdate()) {
|
||||
if (entry.isKeyUpdate() || entry.isKeyDelete()) {
|
||||
auto hash = entry.GetTx().GetHash();
|
||||
for (auto iter = listUnconfirmedKeyValues.begin(); iter != listUnconfirmedKeyValues.end(); ++iter) {
|
||||
if (std::get<0>(*iter) == hash) {
|
||||
@ -190,6 +196,11 @@ CKevaMemPool::checkTx(const CTransaction& tx) const
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_KEVA_DELETE:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert (false);
|
||||
}
|
||||
@ -329,19 +340,29 @@ CheckKevaTransaction (const CTransaction& tx, unsigned nHeight,
|
||||
return state.Invalid (error ("CheckKevaTransaction: key too long"));
|
||||
}
|
||||
|
||||
if (nameOpOut.getOpValue().size () > MAX_VALUE_LENGTH) {
|
||||
return state.Invalid (error ("CheckKevaTransaction: value too long"));
|
||||
const valtype& nameSpace = nameOpOut.getOpNamespace();
|
||||
if (nameSpace != nameOpIn.getOpNamespace()) {
|
||||
return state.Invalid(error("%s: KEVA_PUT namespace mismatch to prev tx found in %s", __func__, txid));
|
||||
}
|
||||
|
||||
/* Process KEVA_PUT next. */
|
||||
const valtype& nameSpace = nameOpOut.getOpNamespace();
|
||||
if (nameOpOut.getKevaOp() == OP_KEVA_PUT) {
|
||||
if (nameOpOut.getOpValue().size () > MAX_VALUE_LENGTH) {
|
||||
return state.Invalid (error ("CheckKevaTransaction: value too long"));
|
||||
}
|
||||
|
||||
if (!nameOpIn.isAnyUpdate() && !nameOpIn.isNamespaceRegistration()) {
|
||||
return state.Invalid(error("CheckKevaTransaction: KEVA_PUT with prev input that is no update"));
|
||||
}
|
||||
}
|
||||
|
||||
if (nameSpace != nameOpIn.getOpNamespace()) {
|
||||
return state.Invalid(error("%s: KEVA_PUT namespace mismatch to prev tx found in %s", __func__, txid));
|
||||
if (nameOpOut.getKevaOp() == OP_KEVA_DELETE) {
|
||||
if (!nameOpIn.isAnyUpdate() && !nameOpIn.isNamespaceRegistration()) {
|
||||
return state.Invalid(error("CheckKevaTransaction: KEVA_DELETE with prev input that is no update"));
|
||||
}
|
||||
CKevaData data;
|
||||
const bool hasKey = view.GetName(nameSpace, nameOpOut.getOpKey(), data);
|
||||
if (!hasKey) {
|
||||
return state.Invalid(error("CheckKevaTransaction: no key to delete"));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -351,7 +372,7 @@ void ApplyKevaTransaction(const CTransaction& tx, unsigned nHeight,
|
||||
CCoinsViewCache& view, CBlockUndo& undo)
|
||||
{
|
||||
assert (nHeight != MEMPOOL_HEIGHT);
|
||||
if (!tx.IsKevacoin ())
|
||||
if (!tx.IsKevacoin())
|
||||
return;
|
||||
|
||||
/* Changes are encoded in the outputs. We don't have to do any checks,
|
||||
@ -362,7 +383,6 @@ void ApplyKevaTransaction(const CTransaction& tx, unsigned nHeight,
|
||||
if (!op.isKevaOp()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (op.isNamespaceRegistration()) {
|
||||
const valtype& nameSpace = op.getOpNamespace();
|
||||
const valtype& displayName = op.getOpNamespaceDisplayName();
|
||||
@ -389,8 +409,12 @@ void ApplyKevaTransaction(const CTransaction& tx, unsigned nHeight,
|
||||
undo.vkevaundo.push_back(opUndo);
|
||||
|
||||
CKevaData data;
|
||||
data.fromScript(nHeight, COutPoint(tx.GetHash(), i), op);
|
||||
view.SetName(nameSpace, key, data, false);
|
||||
if (op.isDelete()) {
|
||||
view.DeleteName(nameSpace, key);
|
||||
} else {
|
||||
data.fromScript(nHeight, COutPoint(tx.GetHash(), i), op);
|
||||
view.SetName(nameSpace, key, data, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -359,6 +359,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||
//
|
||||
case OP_KEVA_NAMESPACE:
|
||||
case OP_KEVA_PUT:
|
||||
case OP_KEVA_DELETE:
|
||||
break;
|
||||
|
||||
case OP_CHECKLOCKTIMEVERIFY:
|
||||
|
@ -55,6 +55,12 @@ CKevaScript::CKevaScript (const CScript& script)
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_KEVA_DELETE:
|
||||
if (args.size() != 2) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_KEVA_NAMESPACE:
|
||||
if (args.size() != 2) {
|
||||
return;
|
||||
@ -79,6 +85,15 @@ CKevaScript::buildKevaPut(const CScript& addr, const valtype& nameSpace,
|
||||
return prefix + addr;
|
||||
}
|
||||
|
||||
CScript
|
||||
CKevaScript::buildKevaDelete(const CScript& addr, const valtype& nameSpace, const valtype& key)
|
||||
{
|
||||
CScript prefix;
|
||||
prefix << OP_KEVA_DELETE << nameSpace << key << OP_2DROP;
|
||||
|
||||
return prefix + addr;
|
||||
}
|
||||
|
||||
CScript CKevaScript::buildKevaNamespace(const CScript& addr, const valtype& nameSpace,
|
||||
const valtype& displayName)
|
||||
{
|
||||
|
@ -66,6 +66,9 @@ public:
|
||||
case OP_KEVA_NAMESPACE:
|
||||
return true;
|
||||
|
||||
case OP_KEVA_DELETE:
|
||||
return true;
|
||||
|
||||
case OP_NOP:
|
||||
return false;
|
||||
|
||||
@ -94,6 +97,9 @@ public:
|
||||
case OP_KEVA_PUT:
|
||||
return op;
|
||||
|
||||
case OP_KEVA_DELETE:
|
||||
return op;
|
||||
|
||||
case OP_KEVA_NAMESPACE:
|
||||
return op;
|
||||
|
||||
@ -115,6 +121,9 @@ public:
|
||||
case OP_KEVA_PUT:
|
||||
return false;
|
||||
|
||||
case OP_KEVA_DELETE:
|
||||
return false;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
@ -133,6 +142,9 @@ public:
|
||||
case OP_KEVA_PUT:
|
||||
return true;
|
||||
|
||||
case OP_KEVA_DELETE:
|
||||
return true;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
@ -149,6 +161,9 @@ public:
|
||||
case OP_KEVA_PUT:
|
||||
return args[0];
|
||||
|
||||
case OP_KEVA_DELETE:
|
||||
return args[0];
|
||||
|
||||
case OP_KEVA_NAMESPACE:
|
||||
return args[0];
|
||||
|
||||
@ -184,6 +199,9 @@ public:
|
||||
case OP_KEVA_PUT:
|
||||
return args[1];
|
||||
|
||||
case OP_KEVA_DELETE:
|
||||
return args[1];
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
@ -206,6 +224,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the keva operation value. This call is only valid for
|
||||
* OP_KEVA_PUT.
|
||||
* @return The keva operation's value.
|
||||
*/
|
||||
inline bool isDelete() const
|
||||
{
|
||||
return (op == OP_KEVA_DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given script is a keva script. This is a utility method.
|
||||
* @param script The script to parse.
|
||||
@ -215,7 +243,7 @@ public:
|
||||
isKevaScript (const CScript& script)
|
||||
{
|
||||
const CKevaScript op(script);
|
||||
return op.isKevaOp ();
|
||||
return op.isKevaOp();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -237,6 +265,15 @@ public:
|
||||
const valtype& key, const valtype& value);
|
||||
|
||||
|
||||
/**
|
||||
* Build a KEVA_DELETE transaction.
|
||||
* @param addr The address script to append.
|
||||
* @param hash The hash to use.
|
||||
* @return The full KEVA_DELETE script.
|
||||
*/
|
||||
static CScript buildKevaDelete(const CScript& addr, const valtype& nameSpace, const valtype& key);
|
||||
|
||||
|
||||
static CScript replaceKevaNamespace(const CScript& oldScript, const uint256& txId, valtype& kaveNamespace, const CChainParams& params);
|
||||
|
||||
};
|
||||
|
@ -186,7 +186,7 @@ enum opcodetype
|
||||
// Keva
|
||||
OP_KEVA_PUT=0xd0,
|
||||
OP_KEVA_NAMESPACE=0xd1,
|
||||
|
||||
OP_KEVA_DELETE=0xd2,
|
||||
|
||||
// template matching params
|
||||
OP_SMALLINTEGER = 0xfa,
|
||||
|
@ -142,6 +142,11 @@ public:
|
||||
return kevaOp.isKevaOp() && kevaOp.getKevaOp() == OP_KEVA_PUT;
|
||||
}
|
||||
|
||||
inline bool isKeyDelete() const
|
||||
{
|
||||
return kevaOp.isKevaOp() && kevaOp.getKevaOp() == OP_KEVA_DELETE;
|
||||
}
|
||||
|
||||
inline const valtype& getNamespace() const
|
||||
{
|
||||
return kevaOp.getOpNamespace();
|
||||
|
@ -42,8 +42,8 @@ UniValue keva_namespace(const JSONRPCRequest& request)
|
||||
"1. \"display_name\" (string, required) the display name of the namespace\n"
|
||||
"\nResult:\n"
|
||||
"[\n"
|
||||
" xxxxx, (string) the txid, required for keva_put\n"
|
||||
" xxxxx, (string) the unique namespace id, required for keva_put\n"
|
||||
" xxxxx, (string) the txid\n"
|
||||
" xxxxx, (string) the unique namespace id\n"
|
||||
"]\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli ("keva_namespace", "\"display name\"")
|
||||
@ -96,8 +96,11 @@ UniValue keva_namespace(const JSONRPCRequest& request)
|
||||
kevaNamespaceBase58.c_str(), displayNameStr.c_str(), txid.c_str());
|
||||
|
||||
UniValue res(UniValue::VARR);
|
||||
res.push_back(txid);
|
||||
res.push_back(kevaNamespaceBase58);
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.pushKV("txid", txid);
|
||||
obj.pushKV("namespaceId", kevaNamespaceBase58);
|
||||
res.push_back(obj);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -207,8 +210,8 @@ UniValue keva_put(const JSONRPCRequest& request)
|
||||
|
||||
if (request.fHelp || request.params.size() != 3) {
|
||||
throw std::runtime_error (
|
||||
"keva_put \"namespace\" \"key\" \"value\" (\"create_namespace\")\n"
|
||||
"\nUpdate a name and possibly transfer it.\n"
|
||||
"keva_put \"namespace\" \"key\" \"value\"\n"
|
||||
"\nInsert or update a key value pair in the given namespace.\n"
|
||||
+ HelpRequiringPassphrase (pwallet) +
|
||||
"\nArguments:\n"
|
||||
"1. \"namespace\" (string, required) the namespace to insert the key to\n"
|
||||
@ -251,7 +254,7 @@ UniValue keva_put(const JSONRPCRequest& request)
|
||||
COutput output;
|
||||
std::string kevaNamespce = namespaceStr;
|
||||
if (!pwallet->FindKevaCoin(output, kevaNamespce)) {
|
||||
throw JSONRPCError (RPC_TRANSACTION_ERROR, "this name can not be updated");
|
||||
throw JSONRPCError (RPC_TRANSACTION_ERROR, "this namespace can not be updated");
|
||||
}
|
||||
const COutPoint outp(output.tx->GetHash(), output.i);
|
||||
const CTxIn txIn(outp);
|
||||
@ -281,6 +284,96 @@ UniValue keva_put(const JSONRPCRequest& request)
|
||||
return wtx.GetHash().GetHex();
|
||||
}
|
||||
|
||||
UniValue keva_delete(const JSONRPCRequest& request)
|
||||
{
|
||||
CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
if (!EnsureWalletIsAvailable (pwallet, request.fHelp)) {
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
if (request.fHelp || request.params.size() != 2) {
|
||||
throw std::runtime_error (
|
||||
"keva_delete \"namespace\" \"key\"\n"
|
||||
"\nRemove the specified key from the given namespace.\n"
|
||||
+ HelpRequiringPassphrase (pwallet) +
|
||||
"\nArguments:\n"
|
||||
"1. \"namespace\" (string, required) the namespace to insert the key to\n"
|
||||
"2. \"key\" (string, required) value for the key\n"
|
||||
"\nResult:\n"
|
||||
"\"txid\" (string) the keva_delete's txid\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli ("keva_delete", "\"mynamespace\", \"key\"")
|
||||
);
|
||||
}
|
||||
|
||||
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR});
|
||||
RPCTypeCheckArgument(request.params[0], UniValue::VSTR);
|
||||
RPCTypeCheckArgument(request.params[1], UniValue::VSTR);
|
||||
|
||||
ObserveSafeMode ();
|
||||
|
||||
const std::string namespaceStr = request.params[0].get_str();
|
||||
valtype nameSpace;
|
||||
if (!DecodeKevaNamespace(namespaceStr, Params(), nameSpace)) {
|
||||
throw JSONRPCError (RPC_INVALID_PARAMETER, "invalid namespace id");
|
||||
}
|
||||
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 ();
|
||||
const valtype key = ValtypeFromString (keyStr);
|
||||
if (key.size () > MAX_KEY_LENGTH) {
|
||||
throw JSONRPCError (RPC_INVALID_PARAMETER, "the key is too long");
|
||||
}
|
||||
|
||||
CKevaData data;
|
||||
{
|
||||
LOCK2(cs_main, mempool.cs);
|
||||
if (!pcoinsTip->GetName(nameSpace, key, data)) {
|
||||
std::vector<std::tuple<valtype, valtype, valtype, uint256>> unconfirmedKeyValueList;
|
||||
valtype val;
|
||||
if (!mempool.getUnconfirmedKeyValue(nameSpace, key, val) || val.size() == 0) {
|
||||
throw JSONRPCError (RPC_TRANSACTION_ERROR, "key not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
|
||||
COutput output;
|
||||
std::string kevaNamespce = namespaceStr;
|
||||
if (!pwallet->FindKevaCoin(output, kevaNamespce)) {
|
||||
throw JSONRPCError (RPC_TRANSACTION_ERROR, "this namespace can not be updated");
|
||||
}
|
||||
const COutPoint outp(output.tx->GetHash(), output.i);
|
||||
const CTxIn txIn(outp);
|
||||
|
||||
CReserveKey keyName(pwallet);
|
||||
CPubKey pubKeyReserve;
|
||||
const bool ok = keyName.GetReservedKey(pubKeyReserve, true);
|
||||
assert(ok);
|
||||
bool usedKey = false;
|
||||
|
||||
CScript addrName;
|
||||
usedKey = true;
|
||||
addrName = GetScriptForDestination(pubKeyReserve.GetID());
|
||||
|
||||
const CScript kevaScript = CKevaScript::buildKevaDelete(addrName, nameSpace, key);
|
||||
|
||||
CCoinControl coinControl;
|
||||
CWalletTx wtx;
|
||||
valtype empty;
|
||||
SendMoneyToScript(pwallet, kevaScript, &txIn, empty,
|
||||
KEVA_LOCKED_AMOUNT, false, wtx, coinControl);
|
||||
|
||||
if (usedKey) {
|
||||
keyName.KeepKey();
|
||||
}
|
||||
|
||||
return wtx.GetHash().GetHex();
|
||||
}
|
||||
|
||||
UniValue keva_get(const JSONRPCRequest& request)
|
||||
{
|
||||
CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
@ -392,6 +485,7 @@ UniValue keva_pending(const JSONRPCRequest& request)
|
||||
UniValue arr(UniValue::VARR);
|
||||
const std::string opKevaNamepsace = "keva_namespace";
|
||||
const std::string opKevaPut = "keva_put";
|
||||
const std::string opKevaDelete = "keva_delete";
|
||||
|
||||
for (auto entry: unconfirmedNamespaces) {
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
@ -404,11 +498,19 @@ UniValue keva_pending(const JSONRPCRequest& request)
|
||||
|
||||
for (auto entry: unconfirmedKeyValueList) {
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.pushKV("op", opKevaPut);
|
||||
obj.pushKV("namespace", EncodeBase58Check(std::get<0>(entry)));
|
||||
obj.pushKV("key", ValtypeToString(std::get<1>(entry)));
|
||||
obj.pushKV("value", ValtypeToString(std::get<2>(entry)));
|
||||
obj.pushKV("txid", std::get<3>(entry).ToString());
|
||||
const valtype val = std::get<2>(entry);
|
||||
if (val.size() > 0) {
|
||||
obj.pushKV("op", opKevaPut);
|
||||
obj.pushKV("namespace", EncodeBase58Check(std::get<0>(entry)));
|
||||
obj.pushKV("key", ValtypeToString(std::get<1>(entry)));
|
||||
obj.pushKV("value", ValtypeToString(std::get<2>(entry)));
|
||||
obj.pushKV("txid", std::get<3>(entry).ToString());
|
||||
} else {
|
||||
obj.pushKV("op", opKevaDelete);
|
||||
obj.pushKV("namespace", EncodeBase58Check(std::get<0>(entry)));
|
||||
obj.pushKV("key", ValtypeToString(std::get<1>(entry)));
|
||||
obj.pushKV("txid", std::get<3>(entry).ToString());
|
||||
}
|
||||
arr.push_back(obj);
|
||||
}
|
||||
|
||||
|
@ -3593,6 +3593,7 @@ extern UniValue rescanblockchain(const JSONRPCRequest& request);
|
||||
// in rpckeva.cpp
|
||||
extern UniValue keva_namespace(const JSONRPCRequest& request);
|
||||
extern UniValue keva_put(const JSONRPCRequest& request);
|
||||
extern UniValue keva_delete(const JSONRPCRequest& request);
|
||||
extern UniValue keva_get(const JSONRPCRequest& request);
|
||||
extern UniValue keva_list_namespaces(const JSONRPCRequest& request);
|
||||
extern UniValue keva_pending(const JSONRPCRequest& request);
|
||||
@ -3658,6 +3659,7 @@ static const CRPCCommand commands[] =
|
||||
{ "kevacoin", "keva_namespace", &keva_namespace, {"display_name"} },
|
||||
{ "kevacoin", "keva_list_namespaces", &keva_list_namespaces, {} },
|
||||
{ "kevacoin", "keva_put", &keva_put, {"namespace", "key", "value"} },
|
||||
{ "kevacoin", "keva_delete", &keva_delete, {"namespace", "key"} },
|
||||
{ "kevacoin", "keva_get", &keva_get, {"namespace", "key"} },
|
||||
{ "kevacoin", "keva_pending", &keva_pending, {"namespace"} }
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user