mirror of
https://github.com/kvazar-network/kevacoin.git
synced 2025-03-12 13:41:52 +00:00
WIP: support two OPs.
This commit is contained in:
parent
4837682b4d
commit
855dc114e9
@ -18,21 +18,6 @@
|
|||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
|
|
||||||
|
|
||||||
/* ************************************************************************** */
|
|
||||||
/* CNameData. */
|
|
||||||
|
|
||||||
bool
|
|
||||||
CNameData::isExpired () const
|
|
||||||
{
|
|
||||||
return isExpired (chainActive.Height ());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CNameData::isExpired (unsigned h) const
|
|
||||||
{
|
|
||||||
return ::isExpired (nHeight, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
/* CNameTxUndo. */
|
/* CNameTxUndo. */
|
||||||
|
|
||||||
@ -152,48 +137,6 @@ CKevaMemPool::removeConflicts (const CTransaction& tx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CKevaMemPool::removeUnexpireConflicts (const std::set<valtype>& unexpired)
|
|
||||||
{
|
|
||||||
AssertLockHeld (pool.cs);
|
|
||||||
|
|
||||||
for (const auto& name : unexpired)
|
|
||||||
{
|
|
||||||
LogPrint (BCLog::NAMES, "unexpired: %s, mempool: %u\n",
|
|
||||||
ValtypeToString (name).c_str (), mapNameRegs.count (name));
|
|
||||||
|
|
||||||
const NameTxMap::const_iterator mit = mapNameRegs.find (name);
|
|
||||||
if (mit != mapNameRegs.end ())
|
|
||||||
{
|
|
||||||
const CTxMemPool::txiter mit2 = pool.mapTx.find (mit->second);
|
|
||||||
assert (mit2 != pool.mapTx.end ());
|
|
||||||
pool.removeRecursive (mit2->GetTx (),
|
|
||||||
MemPoolRemovalReason::NAME_CONFLICT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CKevaMemPool::removeExpireConflicts (const std::set<valtype>& expired)
|
|
||||||
{
|
|
||||||
AssertLockHeld (pool.cs);
|
|
||||||
|
|
||||||
for (const auto& name : expired)
|
|
||||||
{
|
|
||||||
LogPrint (BCLog::NAMES, "expired: %s, mempool: %u\n",
|
|
||||||
ValtypeToString (name).c_str (), mapNameUpdates.count (name));
|
|
||||||
|
|
||||||
const NameTxMap::const_iterator mit = mapNameUpdates.find (name);
|
|
||||||
if (mit != mapNameUpdates.end ())
|
|
||||||
{
|
|
||||||
const CTxMemPool::txiter mit2 = pool.mapTx.find (mit->second);
|
|
||||||
assert (mit2 != pool.mapTx.end ());
|
|
||||||
pool.removeRecursive (mit2->GetTx (),
|
|
||||||
MemPoolRemovalReason::NAME_CONFLICT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CKevaMemPool::check (const CCoinsView& coins) const
|
CKevaMemPool::check (const CCoinsView& coins) const
|
||||||
{
|
{
|
||||||
|
@ -201,21 +201,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void removeConflicts (const CTransaction& tx);
|
void removeConflicts (const CTransaction& tx);
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove conflicts in the mempool due to unexpired names. This removes
|
|
||||||
* conflicting name registrations that are no longer possible.
|
|
||||||
* @param unexpired The set of unexpired names.
|
|
||||||
* @param removed Put removed tx here.
|
|
||||||
*/
|
|
||||||
void removeUnexpireConflicts (const std::set<valtype>& unexpired);
|
|
||||||
/**
|
|
||||||
* Remove conflicts in the mempool due to expired names. This removes
|
|
||||||
* conflicting name updates that are no longer possible.
|
|
||||||
* @param expired The set of expired names.
|
|
||||||
* @param removed Put removed tx here.
|
|
||||||
*/
|
|
||||||
void removeExpireConflicts (const std::set<valtype>& expired);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform sanity checks. Throws if it fails.
|
* Perform sanity checks. Throws if it fails.
|
||||||
* @param coins The coins view this represents.
|
* @param coins The coins view this represents.
|
||||||
|
75
src/script/keva.cpp
Normal file
75
src/script/keva.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright (c) 2014-2017 Daniel Kraft
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <script/keva.h>
|
||||||
|
|
||||||
|
#include <uint256.h>
|
||||||
|
|
||||||
|
CKevaScript::CKevaScript (const CScript& script)
|
||||||
|
: op(OP_NOP), address(script)
|
||||||
|
{
|
||||||
|
opcodetype nameOp;
|
||||||
|
CScript::const_iterator pc = script.begin ();
|
||||||
|
if (!script.GetOp (pc, nameOp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
opcodetype opcode;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
valtype vch;
|
||||||
|
|
||||||
|
if (!script.GetOp (pc, opcode, vch))
|
||||||
|
return;
|
||||||
|
if (opcode == OP_DROP || opcode == OP_2DROP || opcode == OP_NOP)
|
||||||
|
break;
|
||||||
|
if (!(opcode >= 0 && opcode <= OP_PUSHDATA4))
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.push_back (vch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the pc to after any DROP or NOP.
|
||||||
|
while (opcode == OP_DROP || opcode == OP_2DROP || opcode == OP_NOP)
|
||||||
|
if (!script.GetOp (pc, opcode))
|
||||||
|
break;
|
||||||
|
pc--;
|
||||||
|
|
||||||
|
/* Now, we have the args and the operation. Check if we have indeed
|
||||||
|
a valid name operation and valid argument counts. Only now set the
|
||||||
|
op and address members, if everything is valid. */
|
||||||
|
switch (nameOp)
|
||||||
|
{
|
||||||
|
case OP_KEVA_PUT:
|
||||||
|
if (args.size () != 1)
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
op = nameOp;
|
||||||
|
address = CScript (pc, script.end ());
|
||||||
|
}
|
||||||
|
|
||||||
|
CScript
|
||||||
|
CKevaScript::buildKevaPut(const CScript& addr, const valtype& nameSpace,
|
||||||
|
const valtype& key, const valtype& value)
|
||||||
|
{
|
||||||
|
CScript prefix;
|
||||||
|
prefix << OP_KEVA_PUT << nameSpace << key << value
|
||||||
|
<< OP_2DROP << OP_2DROP;
|
||||||
|
|
||||||
|
return prefix + addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CScript CKevaScript::buildKevaNamespace(const CScript& addr, const valtype& nameSpace,
|
||||||
|
const valtype& displayName) {
|
||||||
|
CScript prefix;
|
||||||
|
prefix << OP_KEVA_NAMESPACE << nameSpace << displayName
|
||||||
|
<< OP_2DROP << OP_2DROP;
|
||||||
|
|
||||||
|
return prefix + addr;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,207 @@
|
|||||||
|
// Copyright (c) 2018 Jianping Wu
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef H_BITCOIN_SCRIPT_KEVA
|
||||||
|
#define H_BITCOIN_SCRIPT_KEVA
|
||||||
|
|
||||||
|
#include <script/script.h>
|
||||||
|
|
||||||
|
class uint160;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A script parsed for keva operations. This can be initialised
|
||||||
|
* from a "standard" script, and will then determine if this is
|
||||||
|
* a name operation and which parts it consists of.
|
||||||
|
*/
|
||||||
|
class CKevaScript
|
||||||
|
{
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** The type of operation. OP_NOP if no (valid) name op. */
|
||||||
|
opcodetype op;
|
||||||
|
|
||||||
|
/** The non-name part, i. e., the address. */
|
||||||
|
CScript address;
|
||||||
|
|
||||||
|
/** The operation arguments. */
|
||||||
|
std::vector<valtype> args;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor. This enables us to declare a variable
|
||||||
|
* and initialise it later via assignment.
|
||||||
|
*/
|
||||||
|
inline CKevaScript ()
|
||||||
|
: op(OP_NOP)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a script and determine whether it is a valid name script. Sets
|
||||||
|
* the member variables representing the "picked apart" name script.
|
||||||
|
* @param script The ordinary script to parse.
|
||||||
|
*/
|
||||||
|
explicit CKevaScript (const CScript& script);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether this is a (valid) name script.
|
||||||
|
* @return True iff this is a name operation.
|
||||||
|
*/
|
||||||
|
inline bool
|
||||||
|
isNameOp () const
|
||||||
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case OP_KEVA_PUT:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case OP_NOP:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the non-name script.
|
||||||
|
* @return The address part.
|
||||||
|
*/
|
||||||
|
inline const CScript&
|
||||||
|
getAddress () const
|
||||||
|
{
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name operation. This returns OP_NAME_NEW, OP_NAME_FIRSTUPDATE
|
||||||
|
* or OP_NAME_UPDATE. Do not call if this is not a name script.
|
||||||
|
* @return The name operation opcode.
|
||||||
|
*/
|
||||||
|
inline opcodetype
|
||||||
|
getNameOp () const
|
||||||
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case OP_KEVA_PUT:
|
||||||
|
return op;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether this is a name update (including first updates). I. e.,
|
||||||
|
* whether this creates a name index update/entry.
|
||||||
|
* @return True iff this is NAME_FIRSTUPDATE or NAME_UPDATE.
|
||||||
|
*/
|
||||||
|
inline bool
|
||||||
|
isAnyUpdate () const
|
||||||
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case OP_KEVA_PUT:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name operation name. This call is only valid for
|
||||||
|
* OP_NAME_FIRSTUPDATE or OP_NAME_UPDATE.
|
||||||
|
* @return The name operation's name.
|
||||||
|
*/
|
||||||
|
inline const valtype&
|
||||||
|
getOpName () const
|
||||||
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case OP_KEVA_PUT:
|
||||||
|
return args[0];
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name operation value. This call is only valid for
|
||||||
|
* OP_NAME_FIRSTUPDATE or OP_NAME_UPDATE.
|
||||||
|
* @return The name operation's value.
|
||||||
|
*/
|
||||||
|
inline const valtype&
|
||||||
|
getOpValue () const
|
||||||
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case OP_KEVA_PUT:
|
||||||
|
// args[1] is namespace
|
||||||
|
return args[2];
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name operation's rand value. This is only valid
|
||||||
|
* for OP_NAME_FIRSTUPDATE.
|
||||||
|
* @return The name operation's rand.
|
||||||
|
*/
|
||||||
|
inline const valtype&
|
||||||
|
getOpRand () const
|
||||||
|
{
|
||||||
|
assert (op == OP_NAME_FIRSTUPDATE);
|
||||||
|
return args[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name operation's hash value. This is only valid
|
||||||
|
* for OP_NAME_NEW.
|
||||||
|
* @return The name operation's hash.
|
||||||
|
*/
|
||||||
|
inline const valtype&
|
||||||
|
getOpHash () const
|
||||||
|
{
|
||||||
|
assert (op == OP_NAME_NEW);
|
||||||
|
return args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given script is a name script. This is a utility method.
|
||||||
|
* @param script The script to parse.
|
||||||
|
* @return True iff it is a name script.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
isNameScript (const CScript& script)
|
||||||
|
{
|
||||||
|
const CKevaScript op(script);
|
||||||
|
return op.isNameOp ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a KEVA_NAMESPACE transaction.
|
||||||
|
* @param addr The address script to append.
|
||||||
|
* @param hash The hash to use.
|
||||||
|
* @return The full KEVA_NAMESPACE script.
|
||||||
|
*/
|
||||||
|
static CScript buildKevaNamespace(const CScript& addr, const valtype& nameSpace,
|
||||||
|
const valtype& displayName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a KEVA_PUT transaction.
|
||||||
|
* @param addr The address script to append.
|
||||||
|
* @param hash The hash to use.
|
||||||
|
* @return The full KEVA_PUT script.
|
||||||
|
*/
|
||||||
|
static CScript buildKevaPut(const CScript& addr, const valtype& nameSpace,
|
||||||
|
const valtype& key, const valtype& value);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // H_BITCOIN_SCRIPT_KEVA
|
@ -57,7 +57,9 @@ enum opcodetype
|
|||||||
OP_RESERVED = 0x50,
|
OP_RESERVED = 0x50,
|
||||||
OP_1 = 0x51,
|
OP_1 = 0x51,
|
||||||
OP_TRUE=OP_1,
|
OP_TRUE=OP_1,
|
||||||
|
OP_KEVA_PUT=OP_1,
|
||||||
OP_2 = 0x52,
|
OP_2 = 0x52,
|
||||||
|
OP_KEVA_NAMESPACE=OP_2,
|
||||||
OP_3 = 0x53,
|
OP_3 = 0x53,
|
||||||
OP_4 = 0x54,
|
OP_4 = 0x54,
|
||||||
OP_5 = 0x55,
|
OP_5 = 0x55,
|
||||||
|
@ -22,6 +22,78 @@
|
|||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
UniValue
|
||||||
|
keva_namespace (const JSONRPCRequest& request)
|
||||||
|
{
|
||||||
|
CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
|
||||||
|
if (!EnsureWalletIsAvailable (pwallet, request.fHelp))
|
||||||
|
return NullUniValue;
|
||||||
|
|
||||||
|
if (request.fHelp || request.params.size () != 1)
|
||||||
|
throw std::runtime_error (
|
||||||
|
"keva_namespace \"display_name\"\n"
|
||||||
|
"\nStart creation of the given namespace.\n"
|
||||||
|
+ HelpRequiringPassphrase (pwallet) +
|
||||||
|
"\nArguments:\n"
|
||||||
|
"1. \"display_name\" (string, required) the display name of the namespace\n"
|
||||||
|
"\nResult:\n"
|
||||||
|
"[\n"
|
||||||
|
" xxxxx, (string) the txid, required for keva_put\n"
|
||||||
|
"]\n"
|
||||||
|
"\nExamples:\n"
|
||||||
|
+ HelpExampleCli ("keva_namespace", "\"display name\"")
|
||||||
|
);
|
||||||
|
|
||||||
|
RPCTypeCheck (request.params, {UniValue::VSTR});
|
||||||
|
|
||||||
|
ObserveSafeMode ();
|
||||||
|
|
||||||
|
const std::string nameStr = request.params[0].get_str ();
|
||||||
|
const valtype name = ValtypeFromString (nameStr);
|
||||||
|
if (name.size () > MAX_NAME_LENGTH)
|
||||||
|
throw JSONRPCError (RPC_INVALID_PARAMETER, "the name is too long");
|
||||||
|
|
||||||
|
/* No explicit locking should be necessary. CReserveKey takes care
|
||||||
|
of locking the wallet, and CommitTransaction (called when sending
|
||||||
|
the tx) locks cs_main as necessary. */
|
||||||
|
|
||||||
|
EnsureWalletIsUnlocked (pwallet);
|
||||||
|
|
||||||
|
CReserveKey keyName(pwallet);
|
||||||
|
CPubKey pubKey;
|
||||||
|
const bool ok = keyName.GetReservedKey (pubKey, true);
|
||||||
|
assert (ok);
|
||||||
|
const CScript addrName = GetScriptForDestination (pubKey.GetID ());
|
||||||
|
const CScript newScript = CNameScript::buildNameNew (addrName, hash);
|
||||||
|
|
||||||
|
valtype rand(20);
|
||||||
|
GetRandBytes (&rand[0], rand.size ());
|
||||||
|
|
||||||
|
valtype toHash(rand);
|
||||||
|
toHash.insert (toHash.end (), name.begin (), name.end ());
|
||||||
|
const uint160 hash = Hash160 (toHash);
|
||||||
|
|
||||||
|
CCoinControl coinControl;
|
||||||
|
CWalletTx wtx;
|
||||||
|
SendMoneyToScript (pwallet, newScript, nullptr,
|
||||||
|
NAME_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 ());
|
||||||
|
|
||||||
|
UniValue res(UniValue::VARR);
|
||||||
|
res.push_back (txid);
|
||||||
|
res.push_back (randStr);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
UniValue
|
UniValue
|
||||||
@ -32,7 +104,7 @@ keva_put (const JSONRPCRequest& request)
|
|||||||
return NullUniValue;
|
return NullUniValue;
|
||||||
|
|
||||||
if (request.fHelp
|
if (request.fHelp
|
||||||
|| (request.params.size () != 3 && request.params.size () != 4))
|
|| (request.params.size () != 3))
|
||||||
throw std::runtime_error (
|
throw std::runtime_error (
|
||||||
"keva_put \"namespace\" \"key\" \"value\" (\"create_namespace\")\n"
|
"keva_put \"namespace\" \"key\" \"value\" (\"create_namespace\")\n"
|
||||||
"\nUpdate a name and possibly transfer it.\n"
|
"\nUpdate a name and possibly transfer it.\n"
|
||||||
@ -40,17 +112,15 @@ keva_put (const JSONRPCRequest& request)
|
|||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
"1. \"namespace\" (string, required) the namespace to insert the key to\n"
|
"1. \"namespace\" (string, required) the namespace to insert the key to\n"
|
||||||
"2. \"key\" (string, required) value for the key\n"
|
"2. \"key\" (string, required) value for the key\n"
|
||||||
"4. \"value\" (string, required) value for the name\n"
|
"3. \"value\" (string, required) value for the name\n"
|
||||||
"5. \"create_namespace\" (boolean, optional, default=false) create the namespace if it does not exist yet\n"
|
|
||||||
"\nResult:\n"
|
"\nResult:\n"
|
||||||
"\"txid\" (string) the keva_put's txid\n"
|
"\"txid\" (string) the keva_put's txid\n"
|
||||||
"\nExamples:\n"
|
"\nExamples:\n"
|
||||||
+ HelpExampleCli ("keva_put", "\"mynamespace\", \"new-key\", \"new-value\"")
|
+ HelpExampleCli ("keva_put", "\"mynamespace\", \"new-key\", \"new-value\"")
|
||||||
+ HelpExampleCli ("keva_put", "\"mynamespace\", \"new-key\", \"new-value\", true")
|
|
||||||
);
|
);
|
||||||
|
|
||||||
RPCTypeCheck (request.params,
|
RPCTypeCheck (request.params,
|
||||||
{UniValue::VSTR, UniValue::VSTR, UniValue::VSTR, UniValue::VSTR, UniValue::VBOOL});
|
{UniValue::VSTR, UniValue::VSTR, UniValue::VSTR, UniValue::VSTR});
|
||||||
|
|
||||||
ObserveSafeMode ();
|
ObserveSafeMode ();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user