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

Extra protections against unvalidated access to pricing_record #5

Merged
merged 1 commit into from Jul 14, 2021
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
4 changes: 2 additions & 2 deletions src/cryptonote_core/blockchain.cpp
Expand Up @@ -4720,7 +4720,7 @@ uint64_t Blockchain::get_dynamic_base_fee(uint64_t block_reward, size_t median_b
}

//------------------------------------------------------------------
bool Blockchain::check_fee(size_t tx_weight, uint64_t fee, const offshore::pricing_record pr, const std::string& source, const std::string& dest) const
bool Blockchain::check_fee(size_t tx_weight, uint64_t fee, offshore::pricing_record& pr, const std::string& source, const std::string& dest) const
{
const uint8_t version = get_current_hard_fork_version();

Expand Down Expand Up @@ -4771,7 +4771,7 @@ bool Blockchain::check_fee(size_t tx_weight, uint64_t fee, const offshore::prici
if (source != dest) {
// get_xusd_amount()
boost::multiprecision::uint128_t amount_128 = needed_fee;
boost::multiprecision::uint128_t exchange_128 = pr.unused1; // XHV value moving avg
boost::multiprecision::uint128_t exchange_128 = pr.get_unused1(); // XHV value moving avg
boost::multiprecision::uint128_t result_128 = (amount_128 * exchange_128) / 1000000000000;
needed_fee = (uint64_t)result_128;

Expand Down
2 changes: 1 addition & 1 deletion src/cryptonote_core/blockchain.h
Expand Up @@ -620,7 +620,7 @@ namespace cryptonote
*
* @return true if the fee is enough, false otherwise
*/
bool check_fee(size_t tx_weight, uint64_t fee, const offshore::pricing_record pr, const std::string& source, const std::string& dest) const;
bool check_fee(size_t tx_weight, uint64_t fee, offshore::pricing_record& pr, const std::string& source, const std::string& dest) const;

/**
* @brief check that a transaction's outputs conform to current standards
Expand Down
60 changes: 2 additions & 58 deletions src/cryptonote_core/cryptonote_core.cpp
Expand Up @@ -911,35 +911,7 @@ namespace cryptonote

// NEAC: recover from the reorg during Oracle switch - 1 TX affected
if (pricing_record_height == 821428 && m_nettype == MAINNET) {
const std::string pr_821428 = "9b3f6f2f8f0000003d620e1202000000be71be2555120000b8627010000000000000000000000000ea0885b2270d00000000000000000000f797ff9be00b0000ddbdb005270a0000fc90cfe02b01060000000000000000000000000000000000d0a28224000e000000d643be960e0000002e8bb6a40e000000f8a817f80d00002f5d27d45cdbfbac3d0f6577103f68de30895967d7562fbd56c161ae90130f54301b1ea9d5fd062f37dac75c3d47178bc6f149d21da1ff0e8430065cb762b93a";
pr.xAG = 614976143259;
pr.xAU = 8892867133;
pr.xAUD = 20156914758078;
pr.xBTC = 275800760;
pr.xCAD = 0;
pr.xCHF = 14464149948650;
pr.xCNY = 0;
pr.xEUR = 13059317798903;
pr.xGBP = 11162715471325;
pr.xJPY = 1690137827184892;
pr.xNOK = 0;
pr.xNZD = 0;
pr.xUSD = 15393775330000;
pr.unused1 = 16040600000000;
pr.unused2 = 16100600000000;
pr.unused3 = 15359200000000;
pr.timestamp = 0;
std::string sig = "2f5d27d45cdbfbac3d0f6577103f68de30895967d7562fbd56c161ae90130f54301b1ea9d5fd062f37dac75c3d47178bc6f149d21da1ff0e8430065cb762b93a";
int j=0;
for (unsigned int i = 0; i < sig.size(); i += 2) {
std::string byteString = sig.substr(i, 2);
pr.signature[j++] = (char) strtol(byteString.c_str(), NULL, 16);
}

if (!pr.verifySignature()) {
MERROR_VER("Failed to set correct PR for block: " << pricing_record_height);
return false;
}
pr.set_for_block_821428();
} else {
// Get the correct pricing record here, given the height
std::vector<std::pair<cryptonote::blobdata,block>> blocks_pr;
Expand Down Expand Up @@ -1059,35 +1031,7 @@ namespace cryptonote

// NEAC: recover from the reorg during Oracle switch - 1 TX affected
if (pricing_record_height == 821428 && m_nettype == MAINNET) {
const std::string pr_821428 = "9b3f6f2f8f0000003d620e1202000000be71be2555120000b8627010000000000000000000000000ea0885b2270d00000000000000000000f797ff9be00b0000ddbdb005270a0000fc90cfe02b01060000000000000000000000000000000000d0a28224000e000000d643be960e0000002e8bb6a40e000000f8a817f80d00002f5d27d45cdbfbac3d0f6577103f68de30895967d7562fbd56c161ae90130f54301b1ea9d5fd062f37dac75c3d47178bc6f149d21da1ff0e8430065cb762b93a";
pr.xAG = 614976143259;
pr.xAU = 8892867133;
pr.xAUD = 20156914758078;
pr.xBTC = 275800760;
pr.xCAD = 0;
pr.xCHF = 14464149948650;
pr.xCNY = 0;
pr.xEUR = 13059317798903;
pr.xGBP = 11162715471325;
pr.xJPY = 1690137827184892;
pr.xNOK = 0;
pr.xNZD = 0;
pr.xUSD = 15393775330000;
pr.unused1 = 16040600000000;
pr.unused2 = 16100600000000;
pr.unused3 = 15359200000000;
pr.timestamp = 0;
std::string sig = "2f5d27d45cdbfbac3d0f6577103f68de30895967d7562fbd56c161ae90130f54301b1ea9d5fd062f37dac75c3d47178bc6f149d21da1ff0e8430065cb762b93a";
int j=0;
for (unsigned int i = 0; i < sig.size(); i += 2) {
std::string byteString = sig.substr(i, 2);
pr.signature[j++] = (char) strtol(byteString.c_str(), NULL, 16);
}

if (!pr.verifySignature()) {
MERROR_VER("Failed to set correct PR for block: " << pricing_record_height);
return false;
}
pr.set_for_block_821428();
} else {
// Get the correct pricing record here, given the height
std::vector<std::pair<cryptonote::blobdata,block>> blocks_pr;
Expand Down
10 changes: 5 additions & 5 deletions src/cryptonote_core/cryptonote_tx_utils.cpp
Expand Up @@ -397,7 +397,7 @@ namespace cryptonote
return addr.m_view_public_key;
}
//---------------------------------------------------------------
bool get_offshore_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, const offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t current_height) {
bool get_offshore_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t current_height) {

// Calculate the amount being sent
uint64_t amount = 0;
Expand Down Expand Up @@ -433,7 +433,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
bool get_onshore_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, const offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t current_height) {
bool get_onshore_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t current_height) {

// Calculate the amount being sent
uint64_t amount_usd = 0;
Expand Down Expand Up @@ -471,7 +471,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
bool get_offshore_to_offshore_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, const offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t current_height) {
bool get_offshore_to_offshore_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t current_height) {

// Calculate the amount being sent
auto dsts_copy = dsts;
Expand Down Expand Up @@ -602,7 +602,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
bool get_xasset_to_xusd_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, const offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height) {
bool get_xasset_to_xusd_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height) {

// Calculate the amount being sent
auto dsts_copy = dsts;
Expand Down Expand Up @@ -633,7 +633,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
bool get_xusd_to_xasset_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, const offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height) {
bool get_xusd_to_xasset_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height) {

// Calculate the amount being sent
auto dsts_copy = dsts;
Expand Down
10 changes: 5 additions & 5 deletions src/cryptonote_core/cryptonote_tx_utils.h
Expand Up @@ -168,11 +168,11 @@ namespace cryptonote
crypto::hash get_block_longhash(const Blockchain *pb, const block& b, const uint64_t height, const int miners);
void get_block_longhash_reorg(const uint64_t split_height);

bool get_offshore_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, const offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height);
bool get_onshore_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, const offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height);
bool get_offshore_to_offshore_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, const offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height);
bool get_xasset_to_xusd_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, const offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height);
bool get_xusd_to_xasset_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, const offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height);
bool get_offshore_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height);
bool get_onshore_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height);
bool get_offshore_to_offshore_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height);
bool get_xasset_to_xusd_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height);
bool get_xusd_to_xasset_fee(const std::vector<cryptonote::tx_destination_entry> dsts, const uint32_t unlock_time, offshore::pricing_record &pr, const uint32_t fees_version, uint64_t &fee_estimate, const std::vector<cryptonote::tx_source_entry> sources, const uint64_t height);
bool get_tx_asset_types(const transaction& tx, std::string& source, std::string& destination, const bool is_miner_tx);
bool get_tx_type(const std::string& source, const std::string& destination, bool& offshore, bool& onshore, bool& offshore_transfer, bool& xusd_to_xasset, bool& xasset_to_xusd, bool& xasset_transfer);

Expand Down
35 changes: 3 additions & 32 deletions src/cryptonote_core/tx_pool.cpp
Expand Up @@ -309,7 +309,7 @@ namespace cryptonote

// Block all conversions as of fork 17
if (version >= HF_VERSION_XASSET_FEES_V2) {
LOG_ERROR("Conversion TXs are not permitted as of fork << ",HF_VERSION_XASSET_FEES_V2);
LOG_ERROR("Conversion TXs are not permitted as of fork" << HF_VERSION_XASSET_FEES_V2);
tvc.m_verifivation_failed = true;
return false;
}
Expand Down Expand Up @@ -339,36 +339,7 @@ namespace cryptonote

// NEAC: recover from the reorg during Oracle switch - 1 TX affected
if (tx.pricing_record_height == 821428 && m_blockchain.get_nettype() == MAINNET) {
const std::string pr_821428 = "9b3f6f2f8f0000003d620e1202000000be71be2555120000b8627010000000000000000000000000ea0885b2270d00000000000000000000f797ff9be00b0000ddbdb005270a0000fc90cfe02b01060000000000000000000000000000000000d0a28224000e000000d643be960e0000002e8bb6a40e000000f8a817f80d00002f5d27d45cdbfbac3d0f6577103f68de30895967d7562fbd56c161ae90130f54301b1ea9d5fd062f37dac75c3d47178bc6f149d21da1ff0e8430065cb762b93a";
pr.xAG = 614976143259;
pr.xAU = 8892867133;
pr.xAUD = 20156914758078;
pr.xBTC = 275800760;
pr.xCAD = 0;
pr.xCHF = 14464149948650;
pr.xCNY = 0;
pr.xEUR = 13059317798903;
pr.xGBP = 11162715471325;
pr.xJPY = 1690137827184892;
pr.xNOK = 0;
pr.xNZD = 0;
pr.xUSD = 15393775330000;
pr.unused1 = 16040600000000;
pr.unused2 = 16100600000000;
pr.unused3 = 15359200000000;
pr.timestamp = 0;
std::string sig = "2f5d27d45cdbfbac3d0f6577103f68de30895967d7562fbd56c161ae90130f54301b1ea9d5fd062f37dac75c3d47178bc6f149d21da1ff0e8430065cb762b93a";
int j=0;
for (unsigned int i = 0; i < sig.size(); i += 2) {
std::string byteString = sig.substr(i, 2);
pr.signature[j++] = (char) strtol(byteString.c_str(), NULL, 16);
}

// verify the pr
if (!pr.verifySignature()) {
LOG_ERROR("Failed to set correct PR for block: " << tx.pricing_record_height);
return false;
}
pr.set_for_block_821428();
} else {
// Get the pricing record that was used for conversion
block bl;
Expand All @@ -385,7 +356,7 @@ namespace cryptonote

// check whether we have a valid exchange rate
if (offshore || onshore) {
if (!pr.unused1) { // using 24 hr MA in unused1
if (!pr.get_unused1()) { // using 24 hr MA in unused1
LOG_ERROR("error: empty exchange rate. Conversion not possible.");
tvc.m_verifivation_failed = true;
return false;
Expand Down
143 changes: 142 additions & 1 deletion src/offshore/pricing_record.cpp
Expand Up @@ -99,6 +99,7 @@ namespace offshore
, unused2(0)
, unused3(0)
, timestamp(0)
, validated(false)
{
std::memset(signature, 0, sizeof(signature));
}
Expand Down Expand Up @@ -171,6 +172,36 @@ namespace offshore
std::memcpy(signature, orig.signature, sizeof(signature));
}

void pricing_record::set_for_block_821428()
{
xAG = 614976143259;
xAU = 8892867133;
xAUD = 20156914758078;
xBTC = 275800760;
xCAD = 0;
xCHF = 14464149948650;
xCNY = 0;
xEUR = 13059317798903;
xGBP = 11162715471325;
xJPY = 1690137827184892;
xNOK = 0;
xNZD = 0;
xUSD = 15393775330000;
unused1 = 16040600000000;
unused2 = 16100600000000;
unused3 = 15359200000000;
timestamp = 0;
std::string sig = "2f5d27d45cdbfbac3d0f6577103f68de30895967d7562fbd56c161ae90130f54301b1ea9d5fd062f37dac75c3d47178bc6f149d21da1ff0e8430065cb762b93a";
int j=0;
for (unsigned int i = 0; i < sig.size(); i += 2) {
std::string byteString = sig.substr(i, 2);
signature[j++] = (char) strtol(byteString.c_str(), NULL, 16);
}

// verify the pr
verifySignature();
}

pricing_record& pricing_record::operator=(const pricing_record& orig) noexcept
{
xAG = orig.xAG;
Expand All @@ -194,8 +225,9 @@ namespace offshore
return *this;
}

uint64_t pricing_record::operator[](const std::string asset_type) const
uint64_t pricing_record::operator[](const std::string asset_type)
{
check_validation();
if (asset_type == "XHV") {
return 1000000000000;
} else if (asset_type == "XUSD") {
Expand Down Expand Up @@ -383,4 +415,113 @@ namespace offshore

return false;
}

void pricing_record::check_validation()
{
if(!validated)
verifySignature(NULL);
CHECK_AND_ASSERT_THROW_MES(validated, "Attempting to use unvalidated data");
}

uint64_t pricing_record::get_xAG()
{
check_validation();
return xAG;
}

uint64_t pricing_record::get_xAU()
{
check_validation();
return xAU;
}

uint64_t pricing_record::get_xAUD()
{
check_validation();
return xAUD;
}

uint64_t pricing_record::get_xBTC()
{
check_validation();
return xBTC;
}

uint64_t pricing_record::get_xCAD()
{
check_validation();
return xCAD;
}

uint64_t pricing_record::get_xCHF()
{
check_validation();
return xCHF;
}

uint64_t pricing_record::get_xCNY()
{
check_validation();
return xCNY;
}

uint64_t pricing_record::get_xEUR()
{
check_validation();
return xEUR;
}

uint64_t pricing_record::get_xGBP()
{
check_validation();
return xGBP;
}

uint64_t pricing_record::get_xJPY()
{
check_validation();
return xJPY;
}

uint64_t pricing_record::get_xNOK()
{
check_validation();
return xNOK;
}

uint64_t pricing_record::get_xNZD()
{
check_validation();
return xNZD;
}

uint64_t pricing_record::get_xUSD()
{
check_validation();
return xUSD;
}

uint64_t pricing_record::get_unused1()
{
check_validation();
return unused1;
}

uint64_t pricing_record::get_unused2()
{
check_validation();
return unused2;
}

uint64_t pricing_record::get_unused3()
{
check_validation();
return unused3;
}

uint64_t pricing_record::get_timestamp()
{
check_validation();
return timestamp;
}
}