From ffd59dd15d1ce696266465d60caa31cdd0dd981e Mon Sep 17 00:00:00 2001 From: Bushstar Date: Thu, 7 Dec 2023 10:08:46 +0000 Subject: [PATCH 1/2] Rename pool symbol and name --- src/dfi/consensus/poolpairs.cpp | 27 +++++ src/dfi/poolpairs.h | 6 ++ src/dfi/rpc_poolpair.cpp | 28 +++-- src/dfi/tokens.cpp | 4 +- src/dfi/tokens.h | 2 +- test/functional/feature_poolpair_rename.py | 118 +++++++++++++++++++++ test/functional/test_runner.py | 1 + 7 files changed, 175 insertions(+), 11 deletions(-) create mode 100755 test/functional/feature_poolpair_rename.py diff --git a/src/dfi/consensus/poolpairs.cpp b/src/dfi/consensus/poolpairs.cpp index dfd81766ab4..bd3d0d3c120 100644 --- a/src/dfi/consensus/poolpairs.cpp +++ b/src/dfi/consensus/poolpairs.cpp @@ -115,9 +115,36 @@ Res CPoolPairsConsensus::operator()(const CUpdatePoolPairMessage &obj) const { } } + const auto &consensus = txCtx.GetConsensus(); const auto height = txCtx.GetHeight(); auto &mnview = blockCtx.GetView(); + auto token = mnview.GetToken(obj.poolId); + if (!token) { + return Res::Err("Pool token %d does not exist\n", obj.poolId.v); + } + + const auto tokenUpdated = !obj.pairSymbol.empty() || !obj.pairName.empty(); + if (tokenUpdated) { + if (height < static_cast(consensus.DF23Height)) { + return Res::Err("Poolpair symbol cannot be changed below DF23 height"); + } + } + + if (!obj.pairSymbol.empty()) { + token->symbol = trim_ws(obj.pairSymbol).substr(0, CToken::MAX_TOKEN_POOLPAIR_LENGTH); + } + + if (!obj.pairName.empty()) { + token->name = trim_ws(obj.pairName).substr(0, CToken::MAX_TOKEN_NAME_LENGTH); + } + + if (tokenUpdated) { + if (auto res = mnview.UpdateToken(*token, true); !res) { + return res; + } + } + return mnview.UpdatePoolPair(obj.poolId, height, obj.status, obj.commission, obj.ownerAddress, rewards); } diff --git a/src/dfi/poolpairs.h b/src/dfi/poolpairs.h index 5bd6f8f9f58..ba6c4dd1ae6 100644 --- a/src/dfi/poolpairs.h +++ b/src/dfi/poolpairs.h @@ -123,6 +123,8 @@ struct CUpdatePoolPairMessage { CAmount commission; CScript ownerAddress; CBalances rewards; + std::string pairSymbol; + std::string pairName; ADD_SERIALIZE_METHODS; template @@ -134,6 +136,10 @@ struct CUpdatePoolPairMessage { if (!s.empty()) { READWRITE(rewards); } + if (!s.empty()) { + READWRITE(pairSymbol); + READWRITE(pairName); + } } }; diff --git a/src/dfi/rpc_poolpair.cpp b/src/dfi/rpc_poolpair.cpp index eda7aeef594..4d8e9dbe3b1 100644 --- a/src/dfi/rpc_poolpair.cpp +++ b/src/dfi/rpc_poolpair.cpp @@ -745,6 +745,8 @@ UniValue updatepoolpair(const JSONRPCRequest &request) { RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Token reward to be paid on each block, multiple can be specified."}, + {"name", RPCArg::Type::STR, RPCArg::Optional::NO, "Pool name"}, + {"symbol", RPCArg::Type::STR, RPCArg::Optional::NO, "Pool symbol"}, }, }, { "inputs", @@ -790,6 +792,7 @@ UniValue updatepoolpair(const JSONRPCRequest &request) { CAmount commission = -1; CScript ownerAddress; CBalances rewards; + std::string pairSymbol{}, pairName{}; const UniValue &metaObj = request.params[0].get_obj(); const UniValue &txInputs = request.params[1]; @@ -829,6 +832,12 @@ UniValue updatepoolpair(const JSONRPCRequest &request) { std::numeric_limits::max())); } } + if (!metaObj["symbol"].isNull()) { + pairSymbol = metaObj["symbol"].get_str(); + } + if (!metaObj["name"].isNull()) { + pairName = metaObj["name"].get_str(); + } RejectErc55Address(ownerAddress); const auto txVersion = GetTransactionVersion(targetHeight); @@ -839,19 +848,22 @@ UniValue updatepoolpair(const JSONRPCRequest &request) { rawTx.vin = GetAuthInputsSmart(pwallet, rawTx.nVersion, auths, true, optAuthTx, txInputs, request.metadata.coinSelectOpts); - CDataStream metadata(DfTxMarker, SER_NETWORK, PROTOCOL_VERSION); - metadata << static_cast(CustomTxType::UpdatePoolPair) - // serialize poolId as raw integer - << poolId.v << status << commission << ownerAddress; + CUpdatePoolPairMessage msg; + msg.poolId = poolId; + msg.status = status; + msg.commission = commission; + msg.ownerAddress = ownerAddress; + msg.rewards = rewards; + msg.pairSymbol = pairSymbol; + msg.pairName = pairName; - if (targetHeight >= Params().GetConsensus().DF5ClarkeQuayHeight) { - metadata << rewards; - } + CDataStream metadata(DfTxMarker, SER_NETWORK, PROTOCOL_VERSION); + metadata << static_cast(CustomTxType::UpdatePoolPair) << msg; CScript scriptMeta; scriptMeta << OP_RETURN << ToByteVector(metadata); - rawTx.vout.push_back(CTxOut(0, scriptMeta)); + rawTx.vout.emplace_back(0, scriptMeta); CCoinControl coinControl; diff --git a/src/dfi/tokens.cpp b/src/dfi/tokens.cpp index f3dc7244f00..c5f505a13fd 100644 --- a/src/dfi/tokens.cpp +++ b/src/dfi/tokens.cpp @@ -150,7 +150,7 @@ ResVal CTokensView::CreateToken(const CTokensView::CTokenImpl &token, return {id, Res::Ok()}; } -Res CTokensView::UpdateToken(const CTokenImpl &newToken, bool isPreBayfront, const bool tokenSplitUpdate) { +Res CTokensView::UpdateToken(const CTokenImpl &newToken, bool skipFinalisedCheck, const bool tokenSplitUpdate) { auto pair = GetTokenByCreationTx(newToken.creationTx); if (!pair) { return Res::Err("token with creationTx %s does not exist!", newToken.creationTx.ToString()); @@ -159,7 +159,7 @@ Res CTokensView::UpdateToken(const CTokenImpl &newToken, bool isPreBayfront, con DCT_ID id = pair->first; CTokenImpl &oldToken = pair->second; - if (!isPreBayfront) { + if (!skipFinalisedCheck) { // for compatibility, in potential case when someone cheat and create finalized token with old node (and then // alter dat for ex.) if (oldToken.IsFinalized()) { diff --git a/src/dfi/tokens.h b/src/dfi/tokens.h index 708e2ffd793..692c2a53763 100644 --- a/src/dfi/tokens.h +++ b/src/dfi/tokens.h @@ -199,7 +199,7 @@ class CTokensView : public virtual CStorageView { Res CreateDFIToken(); ResVal CreateToken(const CTokenImpl &token, bool isPreBayfront = false, BlockContext *blockCtx = nullptr); - Res UpdateToken(const CTokenImpl &newToken, bool isPreBayfront = false, const bool tokenSplitUpdate = false); + Res UpdateToken(const CTokenImpl &newToken, bool skipFinalisedCheck = false, const bool tokenSplitUpdate = false); Res BayfrontFlagsCleanup(); Res AddMintedTokens(DCT_ID const &id, const CAmount &amount); diff --git a/test/functional/feature_poolpair_rename.py b/test/functional/feature_poolpair_rename.py new file mode 100755 index 00000000000..dea4a3f141e --- /dev/null +++ b/test/functional/feature_poolpair_rename.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2019 The Bitcoin Core developers +# Copyright (c) DeFi Blockchain Developers +# Distributed under the MIT software license, see the accompanying +# file LICENSE or http://www.opensource.org/licenses/mit-license.php. +"""Test pool pair rename""" + +from test_framework.test_framework import DefiTestFramework + +from test_framework.util import assert_equal, assert_raises_rpc_error + + +class PoolPairRenameTest(DefiTestFramework): + def set_test_params(self): + self.num_nodes = 1 + self.setup_clean_chain = True + self.extra_args = [ + ["-txnotokens=0", "-amkheight=1", "-bayfrontheight=1", "-df23height=110"], + ] + + def run_test(self): + # Set up + self.setup() + + # Rename token + self.rename_token() + + # Rename pool + self.rename_pool() + + def setup(self): + # Generate chain + self.nodes[0].generate(105) + self.sync_blocks() + + # Pool owner address + self.address = self.nodes[0].get_genesis_keys().ownerAuthAddress + + # Create tokens + self.nodes[0].createtoken( + { + "symbol": "FB", + "name": "dFB", + "isDAT": True, + "collateralAddress": self.address, + } + ) + self.nodes[0].createtoken( + { + "symbol": "DUSD", + "name": "Decentralized USD", + "isDAT": True, + "collateralAddress": self.address, + } + ) + self.nodes[0].generate(1) + + # Create pool pair + self.nodes[0].createpoolpair( + { + "tokenA": "FB", + "tokenB": "DUSD", + "comission": 0.001, + "status": True, + "ownerAddress": self.address, + }, + ) + self.nodes[0].generate(1) + + def rename_token(self): + # Rename FB token + self.nodes[0].updatetoken("FB", {"name": "META", "symbol": "dMETA"}) + self.nodes[0].generate(1) + + # Check rename + result = self.nodes[0].gettoken("dMETA")["1"] + assert_equal(result["name"], "META") + assert_equal(result["symbol"], "dMETA") + + def rename_pool(self): + # Rename pool before height + assert_raises_rpc_error( + -32600, + "Poolpair symbol cannot be changed below DF23 height", + self.nodes[0].updatepoolpair, + {"pool": "FB-DUSD", "name": "dMETA-Decentralized USD"}, + ) + assert_raises_rpc_error( + -32600, + "Poolpair symbol cannot be changed below DF23 height", + self.nodes[0].updatepoolpair, + {"pool": "FB-DUSD", "symbol": "META-DUSD"}, + ) + + # Move to fork height + self.nodes[0].generate(2) + + # Rename pool + self.nodes[0].updatepoolpair( + { + "pool": "FB-DUSD", + "name": "dMETA-Decentralized USD", + "symbol": "META-DUSD", + } + ) + self.nodes[0].generate(1) + + # Check new names + result = self.nodes[0].gettoken("META-DUSD")["3"] + assert_equal(result["symbol"], "META-DUSD") + assert_equal(result["name"], "dMETA-Decentralized USD") + result = self.nodes[0].getpoolpair("META-DUSD")["3"] + assert_equal(result["symbol"], "META-DUSD") + assert_equal(result["name"], "dMETA-Decentralized USD") + + +if __name__ == "__main__": + PoolPairRenameTest().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index b45dc014e0e..97539a038c7 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -212,6 +212,7 @@ "rpc_signrawtransaction.py", "wallet_groups.py", "p2p_disconnect_ban.py", + "feature_poolpair_rename.py", "rpc_decodescript.py", "rpc_blockchain.py", "rpc_deprecated.py", From 7c3c3dd134afdec339711cf1fbc1fc657b4f1983 Mon Sep 17 00:00:00 2001 From: Bushstar Date: Wed, 13 Mar 2024 10:25:26 +0000 Subject: [PATCH 2/2] Update call to UpdateToken after merge --- src/dfi/consensus/poolpairs.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dfi/consensus/poolpairs.cpp b/src/dfi/consensus/poolpairs.cpp index 54f5d87fe66..7849f9d0356 100644 --- a/src/dfi/consensus/poolpairs.cpp +++ b/src/dfi/consensus/poolpairs.cpp @@ -142,7 +142,9 @@ Res CPoolPairsConsensus::operator()(const CUpdatePoolPairMessage &obj) const { } if (tokenUpdated) { - if (auto res = mnview.UpdateToken(*token, true); !res) { + BlockContext dummyContext{std::numeric_limits::max(), {}, Params().GetConsensus()}; + UpdateTokenContext ctx{*token, dummyContext, false, false, true}; + if (auto res = mnview.UpdateToken(ctx); !res) { return res; } }