Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Core][GUI][RPC] Exchange Address #2895

Merged
merged 18 commits into from Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 85 additions & 0 deletions doc/release-notes/release-notes-5.6.0.md
@@ -0,0 +1,85 @@
PIVX Core version *v5.6.0* is now available from: <https://github.com/pivx-project/pivx/releases>

This is a new major version release, including various bug fixes and performance improvements, as well as updated translations.

Please report bugs using the issue tracker at github: <https://github.com/pivx-project/pivx/issues>


How to Upgrade
==============

If you are running an older version, shut it down. Wait until it has completely shut down (which might take a few minutes for older versions), then run the installer (on Windows) or just copy over /Applications/PIVX-Qt (on Mac) or pivxd/pivx-qt (on Linux).

Notable Changes
==============

(Developers: add your notes here as part of your pull requests whenever possible)


### Deprecated autocombinerewards RPC Command

The `autocombinerewards` RPC command was soft-deprecated in v5.3.0 and replaced with explicit setter/getter commands `setautocombinethreshold`/`getautocombinethreshold`. PIVX Core, by default, will no longer accept the `autocombinerewards` command, returning a deprecation error, unless the `pivxd`/`pivx-qt` is started with the `-deprecatedrpc=autocombinerewards` option.

This command will be fully removed in v6.0.0.

### Shield address support for RPC label commands

The `setlabel` RPC command now supports a shield address input argument to allow users to set labels for shield addresses. Additionally, the `getaddressesbylabel` RPC command will also now return shield addresses with a matching label.

### Specify optional label for getnewshieldaddress

The `getnewshieldaddress` RPC command now takes an optional argument `label (string)` to denote the desired label for the generated address.

### New getnewexchangeaddress RPC Command

The `getnewexchangeaddress` RPC command has been introduced to create an essentially fully Transparent address to disallow deshielding to in compliance for exchanges. It takes an optional `label (string)` to set a label for the address if necessary. Functionality is the same comparitively to `getnewaddress`, `getnewstakingaddress` and `getnewshieldaddress`

| Command Name | Purpose | Requires Unlocked Wallet? |
| ------------ | ------- | ------------------------- |
| `getnewexchangeaddress` | Creates a new exchange address | Yes |

Command is detailed below:

* `getnewexchangeaddress`
```
Returns a new exchange address for receiving payments.

Result:
"address" (string) The new exchange address.
```

P2P connection management
--------------------------

- Peers manually added through the addnode option or addnode RPC now have their own
limit of sixteen connections which does not compete with other inbound or outbound
connection usage and is not subject to the maxconnections limitation.

- New connections to manually added peers are much faster.

*version* Change log
==============

Detailed release notes follow. This overview includes changes that affect behavior, not code moves, refactors and string updates. For convenience in locating the code changes and accompanying discussion, both the pull request and git merge commit are mentioned.

### Core Features

### Build System

### P2P Protocol and Network Code

### GUI

### RPC/REST
- #2895 Exchange Address `getnewexchangeaddress` (Liquid369)

### Wallet

### Miscellaneous

## Credits

Thanks to everyone who directly contributed to this release:


As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/pivx-project-translations/), the QA team during Testing and the Node hosts supporting our Testnet.
5 changes: 5 additions & 0 deletions src/addressbook.cpp
Expand Up @@ -16,6 +16,7 @@ namespace AddressBook {
const std::string COLD_STAKING_SEND{"coldstaking_send"};
const std::string SHIELDED_RECEIVE{"shielded_receive"};
const std::string SHIELDED_SEND{"shielded_spend"};
const std::string EXCHANGE_ADDRESS{"exchange_address"};
}

bool IsColdStakingPurpose(const std::string& purpose) {
Expand All @@ -28,6 +29,10 @@ namespace AddressBook {
|| purpose == AddressBookPurpose::SHIELDED_SEND;
}

bool IsExchangePurpose(const std::string& purpose) {
return purpose == AddressBookPurpose::EXCHANGE_ADDRESS;
}

bool CAddressBookData::isSendColdStakingPurpose() const {
return purpose == AddressBookPurpose::COLD_STAKING_SEND;
}
Expand Down
2 changes: 2 additions & 0 deletions src/addressbook.h
Expand Up @@ -20,10 +20,12 @@ namespace AddressBook {
extern const std::string COLD_STAKING_SEND;
extern const std::string SHIELDED_RECEIVE;
extern const std::string SHIELDED_SEND;
extern const std::string EXCHANGE_ADDRESS;
}

bool IsColdStakingPurpose(const std::string& purpose);
bool IsShieldedPurpose(const std::string& purpose);
bool IsExchangePurpose(const std::string& purpose);

/** Address book data */
class CAddressBookData {
Expand Down
4 changes: 4 additions & 0 deletions src/blocksignature.cpp
Expand Up @@ -21,6 +21,10 @@ static bool GetKeyIDFromUTXO(const CTxOut& utxo, CKeyID& keyIDRet)
keyIDRet = CKeyID(uint160(vSolutions[0]));
return true;
}
if (whichType == TX_EXCHANGEADDR) {
keyIDRet = CExchangeKeyID(uint160(vSolutions[0]));
return true;
}
return false;
}

Expand Down
6 changes: 6 additions & 0 deletions src/chainparams.cpp
Expand Up @@ -293,6 +293,7 @@ class CMainParams : public CChainParams
consensus.vUpgrades[Consensus::UPGRADE_V5_2].nActivationHeight = 2927000;
consensus.vUpgrades[Consensus::UPGRADE_V5_3].nActivationHeight = 3014000;
consensus.vUpgrades[Consensus::UPGRADE_V5_5].nActivationHeight = 3715200;
consensus.vUpgrades[Consensus::UPGRADE_V5_6].nActivationHeight = 4281680; // Estimate Feb 29th 12:00 UTC
consensus.vUpgrades[Consensus::UPGRADE_V6_0].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;

Expand Down Expand Up @@ -328,6 +329,7 @@ class CMainParams : public CChainParams
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1, 30);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1, 13);
base58Prefixes[STAKING_ADDRESS] = std::vector<unsigned char>(1, 63); // starting with 'S'
base58Prefixes[EXCHANGE_ADDRESS] = {0x01, 0xb9}; // starts with EX
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1, 212);
base58Prefixes[EXT_PUBLIC_KEY] = {0x02, 0x2D, 0x25, 0x33};
base58Prefixes[EXT_SECRET_KEY] = {0x02, 0x21, 0x31, 0x2B};
Expand Down Expand Up @@ -451,6 +453,7 @@ class CTestNetParams : public CChainParams
consensus.vUpgrades[Consensus::UPGRADE_V5_2].nActivationHeight = 262525;
consensus.vUpgrades[Consensus::UPGRADE_V5_3].nActivationHeight = 332300;
consensus.vUpgrades[Consensus::UPGRADE_V5_5].nActivationHeight = 925056;
consensus.vUpgrades[Consensus::UPGRADE_V5_6].nActivationHeight = 1624280; // Estimate Feb 23 Midnight UTC
consensus.vUpgrades[Consensus::UPGRADE_V6_0].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;

Expand All @@ -472,6 +475,7 @@ class CTestNetParams : public CChainParams
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1, 139); // Testnet pivx addresses start with 'x' or 'y'
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1, 19); // Testnet pivx script addresses start with '8' or '9'
base58Prefixes[STAKING_ADDRESS] = std::vector<unsigned char>(1, 73); // starting with 'W'
base58Prefixes[EXCHANGE_ADDRESS] = {0x01, 0xb9, 0xb1}; // EXT prefix for the address
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1, 239); // Testnet private keys start with '9' or 'c' (Bitcoin defaults)
// Testnet pivx BIP32 pubkeys start with 'DRKV'
base58Prefixes[EXT_PUBLIC_KEY] = {0x3a, 0x80, 0x61, 0xa0};
Expand Down Expand Up @@ -601,6 +605,7 @@ class CRegTestParams : public CChainParams
consensus.vUpgrades[Consensus::UPGRADE_V5_2].nActivationHeight = 300;
consensus.vUpgrades[Consensus::UPGRADE_V5_3].nActivationHeight = 251;
consensus.vUpgrades[Consensus::UPGRADE_V5_5].nActivationHeight = 576;
consensus.vUpgrades[Consensus::UPGRADE_V5_6].nActivationHeight = 1000;
consensus.vUpgrades[Consensus::UPGRADE_V6_0].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;

Expand All @@ -618,6 +623,7 @@ class CRegTestParams : public CChainParams
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1, 139); // Testnet pivx addresses start with 'x' or 'y'
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1, 19); // Testnet pivx script addresses start with '8' or '9'
base58Prefixes[STAKING_ADDRESS] = std::vector<unsigned char>(1, 73); // starting with 'W'
base58Prefixes[EXCHANGE_ADDRESS] = {0x01, 0xb9, 0xb1}; // EXT prefix for the address
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1, 239); // Testnet private keys start with '9' or 'c' (Bitcoin defaults)
// Testnet pivx BIP32 pubkeys start with 'DRKV'
base58Prefixes[EXT_PUBLIC_KEY] = {0x3a, 0x80, 0x61, 0xa0};
Expand Down
1 change: 1 addition & 0 deletions src/chainparams.h
Expand Up @@ -51,6 +51,7 @@ class CChainParams
EXT_SECRET_KEY, // BIP32
EXT_COIN_TYPE, // BIP44
STAKING_ADDRESS,
EXCHANGE_ADDRESS,

MAX_BASE58_TYPES
};
Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Expand Up @@ -37,6 +37,7 @@ enum UpgradeIndex : uint32_t {
UPGRADE_V5_2,
UPGRADE_V5_3,
UPGRADE_V5_5,
UPGRADE_V5_6,
UPGRADE_V6_0,
UPGRADE_TESTDUMMY,
// NOTE: Also add new upgrades to NetworkUpgradeInfo in upgrades.cpp
Expand Down
7 changes: 7 additions & 0 deletions src/consensus/tx_verify.cpp
Expand Up @@ -115,9 +115,16 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state, bool fCol
}
}

bool hasExchangeUTXOs = tx.HasExchangeAddr();
int nTxHeight = chainActive.Height();
if (hasExchangeUTXOs && !Params().GetConsensus().NetworkUpgradeActive(nTxHeight, Consensus::UPGRADE_V5_6))
return state.DoS(100, false, REJECT_INVALID, "bad-exchange-address-not-started");

if (tx.IsCoinBase()) {
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 150)
return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
if (hasExchangeUTXOs)
return state.DoS(100, false, REJECT_INVALID, "bad-exchange-address-in-cb");
} else {
for (const CTxIn& txin : tx.vin)
if (txin.prevout.IsNull() && !txin.IsZerocoinSpend())
Expand Down
4 changes: 4 additions & 0 deletions src/consensus/upgrades.cpp
Expand Up @@ -65,6 +65,10 @@ const struct NUInfo NetworkUpgradeInfo[Consensus::MAX_NETWORK_UPGRADES] = {
/*.strName =*/ "PIVX_v5.5",
/*.strInfo =*/ "New rewards structure",
},
{
/*.strName =*/ "PIVX_v5.6",
/*.strInfo =*/ "Exchange address",
},
{
/*.strName =*/ "v6_evo",
/*.strInfo =*/ "Deterministic Masternodes",
Expand Down
17 changes: 11 additions & 6 deletions src/destination_io.cpp
Expand Up @@ -19,20 +19,21 @@ namespace Standard {
CWDestination DecodeDestination(const std::string& strAddress)
{
bool isStaking = false;
return DecodeDestination(strAddress, isStaking);
bool isExchange = false;
return DecodeDestination(strAddress, isStaking, isExchange);
}

CWDestination DecodeDestination(const std::string& strAddress, bool& isStaking)
CWDestination DecodeDestination(const std::string& strAddress, bool& isStaking, bool& isExchange)
{
bool isShielded = false;
return DecodeDestination(strAddress, isStaking, isShielded);
return DecodeDestination(strAddress, isStaking, isExchange, isShielded);
}

// agregar isShielded
CWDestination DecodeDestination(const std::string& strAddress, bool& isStaking, bool& isShielded)
CWDestination DecodeDestination(const std::string& strAddress, bool& isStaking, bool& isExchange, bool& isShielded)
{
CWDestination dest;
CTxDestination regDest = ::DecodeDestination(strAddress, isStaking);
CTxDestination regDest = ::DecodeDestination(strAddress, isStaking, isExchange);
if (!IsValidDestination(regDest)) {
const auto sapDest = KeyIO::DecodeSaplingPaymentAddress(strAddress);
if (sapDest) {
Expand Down Expand Up @@ -70,6 +71,7 @@ Destination& Destination::operator=(const Destination& from)
{
this->dest = from.dest;
this->isP2CS = from.isP2CS;
this->isExchange = from.isExchange;
return *this;
}

Expand All @@ -86,6 +88,9 @@ std::string Destination::ToString() const
// Invalid address
return "";
}
return Standard::EncodeDestination(dest, isP2CS ? CChainParams::STAKING_ADDRESS : CChainParams::PUBKEY_ADDRESS);
CChainParams::Base58Type addrType = isP2CS ? CChainParams::STAKING_ADDRESS
: (isExchange ? CChainParams::EXCHANGE_ADDRESS
: CChainParams::PUBKEY_ADDRESS);
return Standard::EncodeDestination(dest, addrType);
}

6 changes: 4 additions & 2 deletions src/destination_io.h
Expand Up @@ -16,8 +16,8 @@ namespace Standard {
std::string EncodeDestination(const CWDestination &address, const CChainParams::Base58Type addrType = CChainParams::PUBKEY_ADDRESS);

CWDestination DecodeDestination(const std::string& strAddress);
CWDestination DecodeDestination(const std::string& strAddress, bool& isStaking);
CWDestination DecodeDestination(const std::string& strAddress, bool& isStaking, bool& isShielded);
CWDestination DecodeDestination(const std::string& strAddress, bool& isStaking, bool& isExchange);
CWDestination DecodeDestination(const std::string& strAddress, bool& isStaking, bool& isExchange, bool& isShielded);

bool IsValidDestination(const CWDestination& dest);

Expand All @@ -34,10 +34,12 @@ class Destination {
public:
explicit Destination() {}
explicit Destination(const CTxDestination& _dest, bool _isP2CS) : dest(_dest), isP2CS(_isP2CS) {}
explicit Destination(const CTxDestination& _dest, bool _isP2CS, bool _isEXCHANGE = false) : dest(_dest), isP2CS(_isP2CS), isExchange(_isEXCHANGE) {}
explicit Destination(const libzcash::SaplingPaymentAddress& _dest) : dest(_dest) {}

CWDestination dest{CNoDestination()};
bool isP2CS{false};
bool isExchange{false};

Destination& operator=(const Destination& from);
// Returns the key ID if Destination is a transparent "regular" destination
Expand Down
32 changes: 24 additions & 8 deletions src/key_io.cpp
Expand Up @@ -31,6 +31,13 @@ namespace
return EncodeBase58Check(data);
}

std::string operator()(const CExchangeKeyID& id) const
{
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::EXCHANGE_ADDRESS);
data.insert(data.end(), id.begin(), id.end());
return EncodeBase58Check(data);
}

std::string operator()(const CScriptID& id) const
{
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
Expand All @@ -41,11 +48,11 @@ namespace
std::string operator()(const CNoDestination& no) const { return ""; }
};

CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, bool& isStaking)
CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, bool& isStaking, bool& isExchange)
{
std::vector<unsigned char> data;
uint160 hash;
if (DecodeBase58Check(str, data, 21)) {
if (DecodeBase58Check(str, data, 23)) {
// base58-encoded PIVX addresses.
// Public-key-hash-addresses have version 30 (or 139 testnet).
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
Expand All @@ -54,6 +61,13 @@ namespace
std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
return CKeyID(hash);
}
// Exchange Transparent addresses have version 31
const std::vector<unsigned char>& exchange_pubkey_prefix = params.Base58Prefix(CChainParams::EXCHANGE_ADDRESS);
if (data.size() == hash.size() + exchange_pubkey_prefix.size() && std::equal(exchange_pubkey_prefix.begin(), exchange_pubkey_prefix.end(), data.begin())) {
isExchange = true;
std::copy(data.begin() + exchange_pubkey_prefix.size(), data.end(), hash.begin());
return CExchangeKeyID(hash);
}
// Public-key-hash-coldstaking-addresses have version 63 (or 73 testnet).
const std::vector<unsigned char>& staking_prefix = params.Base58Prefix(CChainParams::STAKING_ADDRESS);
if (data.size() == hash.size() + staking_prefix.size() && std::equal(staking_prefix.begin(), staking_prefix.end(), data.begin())) {
Expand All @@ -74,9 +88,9 @@ namespace

} // anon namespace

std::string EncodeDestination(const CTxDestination& dest, bool isStaking)
std::string EncodeDestination(const CTxDestination& dest, bool isStaking, bool isExchange)
{
return EncodeDestination(dest, isStaking ? CChainParams::STAKING_ADDRESS : CChainParams::PUBKEY_ADDRESS);
return isExchange ? EncodeDestination(dest, CChainParams::EXCHANGE_ADDRESS) : (isStaking ? EncodeDestination(dest, CChainParams::STAKING_ADDRESS) : EncodeDestination(dest, CChainParams::PUBKEY_ADDRESS));
}

std::string EncodeDestination(const CTxDestination& dest, const CChainParams::Base58Type addrType)
Expand All @@ -87,18 +101,20 @@ std::string EncodeDestination(const CTxDestination& dest, const CChainParams::Ba
CTxDestination DecodeDestination(const std::string& str)
{
bool isStaking;
return DecodeDestination(str, Params(), isStaking);
bool isExchange;
return DecodeDestination(str, Params(), isStaking, isExchange);
}

CTxDestination DecodeDestination(const std::string& str, bool& isStaking)
CTxDestination DecodeDestination(const std::string& str, bool& isStaking, bool& isExchange)
{
return DecodeDestination(str, Params(), isStaking);
return DecodeDestination(str, Params(), isStaking, isExchange);
}

bool IsValidDestinationString(const std::string& str, bool fStaking, const CChainParams& params)
{
bool isStaking = false;
return IsValidDestination(DecodeDestination(str, params, isStaking)) && (isStaking == fStaking);
bool isExchange = false;
return IsValidDestination(DecodeDestination(str, params, isStaking, isExchange)) && (isStaking == fStaking);
}

bool IsValidDestinationString(const std::string& str, bool isStaking)
Expand Down
6 changes: 3 additions & 3 deletions src/key_io.h
Expand Up @@ -13,10 +13,10 @@

#include <string>

std::string EncodeDestination(const CTxDestination& dest, bool isStaking);
std::string EncodeDestination(const CTxDestination& dest, bool isStaking, bool isExchange);
std::string EncodeDestination(const CTxDestination& dest, const CChainParams::Base58Type addrType = CChainParams::PUBKEY_ADDRESS);
// DecodeDestinationisStaking flag is set to true when the string arg is from an staking address
CTxDestination DecodeDestination(const std::string& str, bool& isStaking);
// DecodeDestination isStaking flag is set to true when the string arg is from an staking address
CTxDestination DecodeDestination(const std::string& str, bool& isStaking, bool& isExchange);
CTxDestination DecodeDestination(const std::string& str);

// Return true if the address is valid and is following the fStaking flag type (true means that the destination must be a staking address, false the opposite).
Expand Down
1 change: 1 addition & 0 deletions src/keystore.h
Expand Up @@ -113,6 +113,7 @@ class CBasicKeyStore : public CKeyStore
bool AddKeyPubKey(const CKey& key, const CPubKey& pubkey);
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
bool HaveKey(const CKeyID& address) const;
bool HaveKey(const CExchangeKeyID& address) const;
std::set<CKeyID> GetKeys() const;
bool GetKey(const CKeyID& address, CKey& keyOut) const;

Expand Down