Skip to content
Open
15 changes: 12 additions & 3 deletions src/evo/assetlocktx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ using node::BlockManager;
/**
* Asset Lock Transaction
*/
bool CheckAssetLockTx(const CTransaction& tx, TxValidationState& state)
bool CheckAssetLockTx(const CTransaction& tx, TxValidationState& state, bool is_v24_active)
{
if (tx.nType != TRANSACTION_ASSET_LOCK) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-assetlocktx-type");
Expand Down Expand Up @@ -56,6 +56,9 @@ bool CheckAssetLockTx(const CTransaction& tx, TxValidationState& state)
if (opt_assetLockTx->getVersion() == 0 || opt_assetLockTx->getVersion() > CAssetLockPayload::CURRENT_VERSION) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-assetlocktx-version");
}
if (!is_v24_active && opt_assetLockTx->getVersion() > CAssetLockPayload::INITIAL_VERSION) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-assetlocktx-version-2");
}

if (opt_assetLockTx->getCreditOutputs().empty()) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-assetlocktx-emptycreditoutputs");
Expand All @@ -68,8 +71,14 @@ bool CheckAssetLockTx(const CTransaction& tx, TxValidationState& state)
}

creditOutputsAmount += out.nValue;
if (!out.scriptPubKey.IsPayToPublicKeyHash()) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-assetlocktx-pubKeyHash");
if (opt_assetLockTx->getVersion() >= 2) {
if (!out.scriptPubKey.IsPayToPublicKeyHash() && !out.scriptPubKey.IsPayToScriptHash()) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-assetlocktx-script-pubkey");
}
} else {
if (!out.scriptPubKey.IsPayToPublicKeyHash()) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-assetlocktx-pubKeyHash");
}
}
}
if (creditOutputsAmount != returnAmount) {
Expand Down
9 changes: 5 additions & 4 deletions src/evo/assetlocktx.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,17 @@ class BlockManager;
class CAssetLockPayload
{
public:
static constexpr uint8_t CURRENT_VERSION = 1;
static constexpr uint8_t INITIAL_VERSION = 1;
static constexpr uint8_t CURRENT_VERSION = 2;
static constexpr auto SPECIALTX_TYPE = TRANSACTION_ASSET_LOCK;

private:
uint8_t nVersion{CURRENT_VERSION};
std::vector<CTxOut> creditOutputs;

public:
explicit CAssetLockPayload(const std::vector<CTxOut>& creditOutputs) :
creditOutputs(creditOutputs)
explicit CAssetLockPayload(const std::vector<CTxOut>& creditOutputs, uint8_t nVersion = CURRENT_VERSION) :
nVersion(nVersion), creditOutputs(creditOutputs)
{}
Comment on lines +40 to 42

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: Move the payload constructor change into the feature commit

Commit 4e48123 is labeled as a regression-test commit but changes the production CAssetLockPayload API to accept an explicit version. Explicit version construction is part of the version-2 implementation and is needed to construct compatible version-1 payloads after CURRENT_VERSION becomes 2. Move this header hunk into 984546b and keep 4e48123 limited to tests.

source: ['codex']


CAssetLockPayload() = default;
Expand Down Expand Up @@ -154,7 +155,7 @@ class CAssetUnlockPayload
}
};

bool CheckAssetLockTx(const CTransaction& tx, TxValidationState& state);
bool CheckAssetLockTx(const CTransaction& tx, TxValidationState& state, bool is_v24_active);
bool CheckAssetUnlockTx(const node::BlockManager& blockman, const llmq::CQuorumManager& qman, const CTransaction& tx, gsl::not_null<const CBlockIndex*> pindexPrev, const std::optional<CRangesSet>& indexes, TxValidationState& state);
bool GetAssetUnlockFee(const CTransaction& tx, CAmount& txfee, TxValidationState& state);

Expand Down
12 changes: 11 additions & 1 deletion src/evo/core_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
#include <util/std23.h>

#include <core_io.h>
#include <key_io.h>
#include <rpc/util.h>
#include <script/standard.h>
#include <util/check.h>

#include <univalue.h>
Expand Down Expand Up @@ -114,7 +116,9 @@ RPCResult CAssetLockPayload::GetJsonHelp(const std::string& key, bool optional)
{RPCResult::Type::STR, "asm", "The asm"},
{RPCResult::Type::STR_HEX, "hex", "The hex"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
}}}}}}
}},
{RPCResult::Type::STR, "address", /*optional=*/true, "DIP-18 Platform address (version >= 2 only)"},
}}}}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}};
}

Expand All @@ -128,6 +132,12 @@ UniValue CAssetLockPayload::ToJson() const
UniValue spk(UniValue::VOBJ);
ScriptToUniv(credit_output.scriptPubKey, spk, /*include_hex=*/true, /*include_address=*/false);
out.pushKV("scriptPubKey", spk);
if (nVersion >= 2) {
if (const PlatformDestination dest = PlatformDestinationFromScript(credit_output.scriptPubKey);
IsValidPlatformDestination(dest)) {
out.pushKV("address", EncodePlatformDestination(dest));
}
}
outputs.push_back(out);
}

Expand Down
2 changes: 1 addition & 1 deletion src/evo/specialtxman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ static bool CheckSpecialTxInner(CDeterministicMNManager& dmnman, llmq::CQuorumSn
case TRANSACTION_MNHF_SIGNAL:
return CheckMNHFTx(chainman, qman, tx, pindexPrev, state);
case TRANSACTION_ASSET_LOCK:
return CheckAssetLockTx(tx, state);
return CheckAssetLockTx(tx, state, DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_V24));
case TRANSACTION_ASSET_UNLOCK:
return CheckAssetUnlockTx(chainman.m_blockman, qman, tx, pindexPrev, indexes, state);
}
Expand Down
5 changes: 5 additions & 0 deletions src/interfaces/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,11 @@ class Chain
//! Relay dust fee setting (-dustrelayfee), reflecting lowest rate it's economical to spend.
virtual CFeeRate relayDustFee() = 0;

//! Whether the mempool would reject this special transaction as non-standard
//! under the current policy (-acceptnonstdtxn), and if so, the reject reason.
//! Always false when non-standard transactions are accepted.
virtual bool isNonStandardSpecialTx(const CTransactionRef& tx, std::string& reason) = 0;

//! Check if any block has been pruned.
virtual bool havePruned() = 0;

Expand Down
24 changes: 24 additions & 0 deletions src/key_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,3 +304,27 @@ PlatformDestination DecodePlatformDestination(const std::string& str)
std::string error_str;
return DecodePlatformDestination(str, error_str);
}

CScript GetScriptForPlatformDestination(const PlatformDestination& dest)
{
if (const auto* pkh = std::get_if<PlatformP2PKHDestination>(&dest)) {
return GetScriptForDestination(PKHash(uint160(*pkh)));
}
if (const auto* sh = std::get_if<PlatformP2SHDestination>(&dest)) {
return GetScriptForDestination(ScriptHash(uint160(*sh)));
}
return {};
}

PlatformDestination PlatformDestinationFromScript(const CScript& script)
{
CTxDestination dest;
if (!ExtractDestination(script, dest)) return CNoDestination();
if (const auto* pkh = std::get_if<PKHash>(&dest)) {
return PlatformP2PKHDestination(uint160(*pkh));
}
if (const auto* sh = std::get_if<ScriptHash>(&dest)) {
return PlatformP2SHDestination(uint160(*sh));
}
return CNoDestination();
}
5 changes: 5 additions & 0 deletions src/key_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,9 @@ PlatformDestination DecodePlatformDestination(const std::string& str);
PlatformDestination DecodePlatformDestination(const std::string& str, std::string& error_str);
PlatformDestination DecodePlatformDestination(const std::string& str, const CChainParams& params, std::string& error_str);

/** The credit output script an asset lock carries for this Platform destination. */
CScript GetScriptForPlatformDestination(const PlatformDestination& dest);
/** Inverse of GetScriptForPlatformDestination; CNoDestination for any other script. */
PlatformDestination PlatformDestinationFromScript(const CScript& script);

#endif // BITCOIN_KEY_IO_H
6 changes: 6 additions & 0 deletions src/node/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <evo/chainhelper.h>
#include <evo/creditpool.h>
#include <evo/deterministicmns.h>
#include <evo/specialtxman.h>
#include <external_signer.h>
#include <governance/governance.h>
#include <governance/object.h>
Expand Down Expand Up @@ -1435,6 +1436,11 @@ class ChainImpl : public Chain
if (!m_node.mempool) return CFeeRate{DUST_RELAY_TX_FEE};
return m_node.mempool->m_dust_relay_feerate;
}
bool isNonStandardSpecialTx(const CTransactionRef& tx, std::string& reason) override
{
if (!m_node.mempool || !m_node.mempool->m_require_standard) return false;
return !IsStandardSpecialTx(*tx, reason);
}
bool havePruned() override
{
LOCK(::cs_main);
Expand Down
16 changes: 11 additions & 5 deletions src/rpc/output_script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static RPCHelpMan validateaddress()
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::BOOL, "isvalid", "If the address is valid or not"},
{RPCResult::Type::BOOL, "isplatform", /*optional=*/true, "If the address is a DIP-18 Dash Platform address"},
{RPCResult::Type::STR, "address", /*optional=*/true, "The Dash address validated"},
{RPCResult::Type::STR_HEX, "scriptPubKey", /*optional=*/true, "The hex-encoded scriptPubKey generated by the address"},
{RPCResult::Type::BOOL, "isscript", /*optional=*/true, "If the key is a script"},
Expand All @@ -51,24 +52,29 @@ static RPCHelpMan validateaddress()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::string address = request.params[0].get_str();
std::string error_msg;
std::vector<int> error_locations;
CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg, &error_locations);
CTxDestination dest = DecodeDestination(address, error_msg, &error_locations);
const bool isValid = IsValidDestination(dest);
CHECK_NONFATAL(isValid == error_msg.empty());

UniValue ret(UniValue::VOBJ);
ret.pushKV("isvalid", isValid);
if (isValid) {
std::string currentAddress = EncodeDestination(dest);
ret.pushKV("address", currentAddress);
ret.pushKV("isvalid", true);
ret.pushKV("address", EncodeDestination(dest));

CScript scriptPubKey = GetScriptForDestination(dest);
ret.pushKV("scriptPubKey", HexStr(scriptPubKey));

UniValue detail = DescribeAddress(dest);
ret.pushKVs(detail);
} else if (const PlatformDestination platform_dest = DecodePlatformDestination(address);
IsValidPlatformDestination(platform_dest)) {
ret.pushKV("isvalid", true);
ret.pushKV("isplatform", true);
ret.pushKV("address", EncodePlatformDestination(platform_dest));
} else {
ret.pushKV("isvalid", false);
UniValue error_indices(UniValue::VARR);
for (int i : error_locations) error_indices.push_back(i);
ret.pushKV("error_locations", error_indices);
Expand Down
Loading
Loading