Skip to content

Commit

Permalink
rpc: Enable checkkernel RPC call
Browse files Browse the repository at this point in the history
  • Loading branch information
lateminer committed Feb 15, 2024
1 parent 5725cd8 commit f592476
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 155 deletions.
2 changes: 2 additions & 0 deletions src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "echojson", 9, "arg9" },
{ "rescanblockchain", 0, "start_height"},
{ "rescanblockchain", 1, "stop_height"},
{ "checkkernel", 0, "inputs" },
{ "checkkernel", 1, "createblocktemplate" },
{ "createwallet", 1, "disable_private_keys"},
{ "createwallet", 2, "blank"},
{ "createwallet", 4, "avoid_reuse"},
Expand Down
155 changes: 0 additions & 155 deletions src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1021,157 +1021,6 @@ static RPCHelpMan submitheader()
};
}

// Blackcoin: checkkernel RPC
// Blackcoin ToDo: check and fix if needed
/*
static RPCHelpMan checkkernel()
{
return RPCHelpMan{"checkkernel",
"\nCheck if one of given inputs is a kernel input at the moment.\n",
{
{"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The inputs",
{
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
{"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
{"sequence", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "depends on the value of the 'locktime' argument", "The sequence number"},
}},
},
},
{"createblocktemplate", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create block template?"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::BOOL, "found", "?"},
{RPCResult::Type::OBJ, "kernel", "",
{
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
{RPCResult::Type::NUM, "vout", "?"},
{RPCResult::Type::NUM, "time", "?"},
}},
{RPCResult::Type::STR_HEX, "blocktemplate", "?"},
{RPCResult::Type::NUM, "blocktemplatefees", "?"},
},
},
RPCExamples{
HelpExampleCli("checkkernel", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"false\"")
+ HelpExampleCli("checkkernel", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"true\"")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
NodeContext& node = EnsureAnyNodeContext(request.context);
const CTxMemPool& mempool = EnsureMemPool(node);
ChainstateManager& chainman = EnsureChainman(node);
LOCK(cs_main);
const CChain& active_chain = chainman.ActiveChain();
Chainstate& active_chainstate = chainman.ActiveChainstate();
UniValue inputs = request.params[0].get_array();
bool fCreateBlockTemplate = request.params.size() > 1 ? request.params[1].get_bool() : false;
if (!Params().IsTestChain()) {
const CConnman& connman = EnsureConnman(node);
if (connman.GetNodeCount(ConnectionDirection::Both) == 0) {
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
}
if (active_chainstate.IsInitialBlockDownload()) {
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks...");
}
}
COutPoint kernel;
CBlockIndex* pindexPrev = active_chain.Tip();
unsigned int nBits = GetNextTargetRequired(pindexPrev, Params().GetConsensus(), true);
int64_t nTime = GetAdjustedTimeSeconds();
nTime &= ~Params().GetConsensus().nStakeTimestampMask;
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
const UniValue& o = input.get_obj();
const UniValue& txid_v = find_value(o, "txid");
if (!txid_v.isStr())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
string txid = txid_v.get_str();
if (!IsHex(txid))
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
const UniValue& vout_v = find_value(o, "vout");
if (!vout_v.isNum())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
int nOutput = vout_v.getInt<int>();
if (nOutput < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
COutPoint cInput(uint256S(txid), nOutput);
if (CheckKernel(pindexPrev, nBits, nTime, cInput, active_chainstate.CoinsTip()))
{
kernel = cInput;
break;
}
}
UniValue result(UniValue::VOBJ);
result.pushKV("found", !kernel.IsNull());
if (kernel.IsNull())
return result;
UniValue oKernel(UniValue::VOBJ);
oKernel.pushKV("txid", kernel.hash.GetHex());
oKernel.pushKV("vout", (int64_t)kernel.n);
oKernel.pushKV("time", nTime);
result.pushKV("kernel", oKernel);
if (!fCreateBlockTemplate)
return result;
#ifdef ENABLE_WALLET
std::shared_ptr<CWallet> const wallet = wallet::GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!pwallet)
return result;
if (!pwallet->IsLocked())
pwallet->TopUpKeyPool();
std::unique_ptr<CBlockTemplate> pblocktemplate;
bool fPoSCancel = false;
int64_t nFees;
pblocktemplate = BlockAssembler{active_chainstate, &mempool}.CreateNewBlock(CScript(), pwallet, &fPoSCancel, &nFees);
if (!pblocktemplate)
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block;
CMutableTransaction coinstakeTx(*pblock->vtx[0]);
pblock->nTime = coinstakeTx.nTime = nTime;
pblock->vtx[0] = MakeTransactionRef(std::move(coinstakeTx));
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
ss << *pblock;
result.pushKV("blocktemplate", HexStr(ss));
result.pushKV("blocktemplatefees", nFees);
// Blackcoin: the reserved key concept is not used in modern Bitcoin Core
CPubKey pubkey;
if (!pMiningKey->GetReservedKey(pubkey))
throw JSONRPCError(RPC_MISC_ERROR, "GetReservedKey failed");
result.push_back(Pair("blocktemplatesignkey", HexStr(pubkey)));
#endif
return result;
},
};
}
*/

void RegisterMiningRPCCommands(CRPCTable& t)
{
static const CRPCCommand commands[]{
Expand All @@ -1185,10 +1034,6 @@ void RegisterMiningRPCCommands(CRPCTable& t)
{"hidden", &generatetodescriptor},
{"hidden", &generateblock},
{"hidden", &generate},

/*
{"staking", &checkkernel},
*/
};
for (const auto& c : commands) {
t.appendCommand(c.name, &c);
Expand Down
157 changes: 157 additions & 0 deletions src/wallet/rpc/staking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <wallet/wallet.h>
#include <node/context.h>
#include <node/miner.h>
#include <key_io.h> // For EncodeDestination
#include <pow.h> // For GetNextTargetRequired
#include <warnings.h>

#include <univalue.h>
Expand Down Expand Up @@ -203,6 +205,160 @@ static RPCHelpMan reservebalance()
};
}

static RPCHelpMan checkkernel()
{
return RPCHelpMan{"checkkernel",
"\nCheck if one of given inputs is a kernel input at the moment.\n",
{
{"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The inputs",
{
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
{"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
{"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'locktime' argument"}, "The sequence number"},
},
},
},
},
{"createblocktemplate", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create block template?"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::BOOL, "found", "?"},
{RPCResult::Type::OBJ, "kernel", "",
{
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
{RPCResult::Type::NUM, "vout", "?"},
{RPCResult::Type::NUM, "time", "?"},
}},
{RPCResult::Type::STR_HEX, "blocktemplate", "?"},
{RPCResult::Type::NUM, "blocktemplatefees", "?"},
},
},
RPCExamples{
HelpExampleCli("checkkernel", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"false\"")
+ HelpExampleCli("checkkernel", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"true\"")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return NullUniValue;

const CTxMemPool& mempool = pwallet->chain().mempool();
ChainstateManager& chainman = pwallet->chain().chainman();
LOCK(cs_main);
const CChain& active_chain = chainman.ActiveChain();
Chainstate& active_chainstate = chainman.ActiveChainstate();

UniValue inputs = request.params[0].get_array();
bool fCreateBlockTemplate = request.params.size() > 1 ? request.params[1].get_bool() : false;

if (!Params().IsTestChain()) {
if (pwallet->chain().getNodeCount(ConnectionDirection::Both) == 0) {
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
}

if (chainman.IsInitialBlockDownload()) {
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks...");
}
}

COutPoint kernel;
CBlockIndex* pindexPrev = active_chain.Tip();
unsigned int nBits = GetNextTargetRequired(pindexPrev, Params().GetConsensus(), true);
int64_t nTime = GetAdjustedTimeSeconds();
nTime &= ~Params().GetConsensus().nStakeTimestampMask;

for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& o = inputs[idx].get_obj();

const UniValue& txid_v = o.find_value("txid");
if (!txid_v.isStr())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
string txid = txid_v.get_str();
if (!IsHex(txid))
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");

const UniValue& vout_v = o.find_value("vout");
if (!vout_v.isNum())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
int nOutput = vout_v.getInt<int>();
if (nOutput < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");

COutPoint cInput(uint256S(txid), nOutput);
if (CheckKernel(pindexPrev, nBits, nTime, cInput, active_chainstate.CoinsTip()))
{
kernel = cInput;
break;
}
}

UniValue result(UniValue::VOBJ);
result.pushKV("found", !kernel.IsNull());

if (kernel.IsNull())
return result;

UniValue oKernel(UniValue::VOBJ);
oKernel.pushKV("txid", kernel.hash.GetHex());
oKernel.pushKV("vout", (int64_t)kernel.n);
oKernel.pushKV("time", nTime);
result.pushKV("kernel", oKernel);

if (!fCreateBlockTemplate)
return result;

if (!pwallet->IsLocked())
pwallet->TopUpKeyPool();

bool fPoSCancel = false;
int64_t nFees;
std::unique_ptr<node::CBlockTemplate> pblocktemplate(BlockAssembler{active_chainstate, &mempool}.CreateNewBlock(CScript(), nullptr, &fPoSCancel, &nFees));
if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");

CBlock *pblock = &pblocktemplate->block;
CMutableTransaction coinstakeTx(*pblock->vtx[0]);
pblock->nTime = coinstakeTx.nTime = nTime;
pblock->vtx[0] = MakeTransactionRef(std::move(coinstakeTx));

CDataStream ss(SER_DISK, PROTOCOL_VERSION);
ss << *pblock;

result.pushKV("blocktemplate", HexStr(ss));
result.pushKV("blocktemplatefees", nFees);

if (!pwallet->CanGetAddresses(true)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
}

// Prepare legacy reserve destination
auto op_dest = pwallet->GetNewChangeDestination(OutputType::LEGACY);
if (!op_dest) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Keypool ran out, please call keypoolrefill first");
}
std::vector<valtype> vSolutionsTmp;
CScript scriptPubKeyTmp = GetScriptForDestination(*op_dest);
Solver(scriptPubKeyTmp, vSolutionsTmp);
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKeyTmp);
if (!provider) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: failed to get signing provider");
}
CKeyID ckey = CKeyID(uint160(vSolutionsTmp[0]));
CPubKey pkey;
if (!provider.get()->GetPubKey(ckey, pkey)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: failed to get key");
}
result.pushKV("blocktemplatesignkey", HexStr(pkey));

return result;
},
};
}

Span<const CRPCCommand> GetStakingRPCCommands()
{
// clang-format off
Expand All @@ -212,6 +368,7 @@ static const CRPCCommand commands[] =
{ "staking", &getstakinginfo, },
{ "staking", &reservebalance, },
{ "staking", &staking, },
{ "staking", &checkkernel, },
};
// clang-format on
return commands;
Expand Down

0 comments on commit f592476

Please sign in to comment.