working premine; empty first version of PROTOCOL_TX in block

This commit is contained in:
Some Random Crypto Guy
2023-10-18 10:48:16 +01:00
parent d186cf95c1
commit 0b3633ccdc
667 changed files with 8288 additions and 5019 deletions
+233
View File
@@ -0,0 +1,233 @@
// Copyright (c) 2019, Haven Protocol
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Portions of this code based upon code Copyright (c) 2019, The Monero Project
#include "pricing_record.h"
#include "serialization/keyvalue_serialization.h"
#include "storages/portable_storage.h"
#include "string_tools.h"
namespace oracle
{
namespace
{
struct pr_serialized
{
uint64_t pr_version;
uint64_t spot;
uint64_t moving_average;
uint64_t timestamp;
std::string signature;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(pr_version)
KV_SERIALIZE(spot)
KV_SERIALIZE(moving_average)
KV_SERIALIZE(timestamp)
KV_SERIALIZE(signature)
END_KV_SERIALIZE_MAP()
};
}
pricing_record::pricing_record() noexcept
: pr_version(0)
, spot(0)
, moving_average(0)
, timestamp(0)
{
std::memset(signature, 0, sizeof(signature));
}
bool pricing_record::_load(epee::serialization::portable_storage& src, epee::serialization::section* hparent)
{
pr_serialized in{};
if (in._load(src, hparent))
{
// Copy everything into the local instance
pr_version = in.pr_version;
spot = in.spot;
moving_average = in.moving_average;
timestamp = in.timestamp;
for (unsigned int i = 0; i < in.signature.length(); i += 2) {
std::string byteString = in.signature.substr(i, 2);
signature[i>>1] = (char) strtol(byteString.c_str(), NULL, 16);
}
return true;
}
// Report error here?
return false;
}
bool pricing_record::store(epee::serialization::portable_storage& dest, epee::serialization::section* hparent) const
{
std::string sig_hex;
for (unsigned int i=0; i<64; i++) {
std::stringstream ss;
ss << std::hex << std::setw(2) << std::setfill('0') << (0xff & signature[i]);
sig_hex += ss.str();
}
const pr_serialized out{pr_version,spot,moving_average,timestamp,sig_hex};
return out.store(dest, hparent);
}
pricing_record::pricing_record(const pricing_record& orig) noexcept
: pr_version(orig.pr_version)
, spot(orig.spot)
, moving_average(orig.moving_average)
, timestamp(orig.timestamp)
{
std::memcpy(signature, orig.signature, sizeof(signature));
}
pricing_record& pricing_record::operator=(const pricing_record& orig) noexcept
{
pr_version = orig.pr_version;
spot = orig.spot;
moving_average = orig.moving_average;
timestamp = orig.timestamp;
::memcpy(signature, orig.signature, sizeof(signature));
return *this;
}
bool pricing_record::equal(const pricing_record& other) const noexcept
{
return ((pr_version == other.pr_version) &&
(spot == other.spot) &&
(moving_average == other.moving_average) &&
(timestamp == other.timestamp) &&
(!::memcmp(signature, other.signature, sizeof(signature))));
}
bool pricing_record::empty() const noexcept
{
const pricing_record empty_pr = oracle::pricing_record();
return (*this).equal(empty_pr);
}
bool pricing_record::verifySignature(const std::string& public_key) const
{
CHECK_AND_ASSERT_THROW_MES(!public_key.empty(), "Pricing record verification failed. NULL public key. PK Size: " << public_key.size()); // TODO: is this necessary or the one below already covers this case, meannin it will produce empty pubkey?
// extract the key
EVP_PKEY* pubkey;
BIO* bio = BIO_new_mem_buf(public_key.c_str(), public_key.size());
if (!bio) {
return false;
}
pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
BIO_free(bio);
CHECK_AND_ASSERT_THROW_MES(pubkey != NULL, "Pricing record verification failed. NULL public key.");
// Convert our internal 64-byte binary representation into 128-byte hex string
std::string sig_hex;
for (unsigned int i=0; i<64; i++) {
std::stringstream ss;
ss << std::hex << std::setw(2) << std::setfill('0') << (0xff & signature[i]);
sig_hex += ss.str();
}
// Build the JSON string, so that we can verify the signature
std::ostringstream oss;
oss << "{\"pr_version\":" << pr_version;
oss << ",\"spot\":" << spot;
oss << ",\"moving_average\":" << moving_average;
oss << ",\"timestamp\":" << timestamp;
oss << "}";
std::string message = oss.str();
// Create a verify digest from the message
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
int ret = 0;
if (ctx) {
ret = EVP_DigestVerifyInit(ctx, NULL, EVP_sha256(), NULL, pubkey);
if (ret == 1) {
ret = EVP_DigestVerifyUpdate(ctx, message.data(), message.length());
if (ret == 1) {
ret = EVP_DigestVerifyFinal(ctx, (const unsigned char *)signature, 64);
}
}
}
// Cleanup the context we created
EVP_MD_CTX_destroy(ctx);
// Cleanup the openssl stuff
EVP_PKEY_free(pubkey);
if (ret == 1)
return true;
// Get the errors from OpenSSL
ERR_print_errors_fp (stderr);
return false;
}
bool pricing_record::has_missing_rates() const noexcept
{
return (spot == 0) || (moving_average == 0);
}
// overload for pr validation for block
bool pricing_record::valid(cryptonote::network_type nettype, uint32_t hf_version, uint64_t bl_timestamp, uint64_t last_bl_timestamp) const
{
if (hf_version < HF_VERSION_SLIPPAGE_YIELD) {
if (!this->empty())
return false;
}
if (this->empty())
return true;
if (this->has_missing_rates()) {
LOG_ERROR("Pricing record has missing rates.");
return false;
}
if (!verifySignature(get_config(nettype).ORACLE_PUBLIC_KEY)) {
LOG_ERROR("Invalid pricing record signature.");
return false;
}
// validate the timestmap
if (this->timestamp > bl_timestamp + PRICING_RECORD_VALID_TIME_DIFF_FROM_BLOCK) {
LOG_ERROR("Pricing record timestamp is too far in the future.");
return false;
}
if (this->timestamp <= last_bl_timestamp) {
LOG_ERROR("Pricing record timestamp: " << this->timestamp << ", block timestamp: " << bl_timestamp);
LOG_ERROR("Pricing record timestamp is too old.");
return false;
}
return true;
}
}