diff --git a/index.js b/index.js index 98ef81a..bece0b1 100644 --- a/index.js +++ b/index.js @@ -189,4 +189,14 @@ module.exports.EthBlockTemplate = function(rpcData) { difficulty: difficulty, height: parseInt(rpcData[3]) }; +}; + +module.exports.ErgBlockTemplate = function(rpcData) { + const difficulty = module.exports.baseDiff().div(bignum(rpcData.b)).toNumber(); + return { + hash: rpcData.msg, + hash2: rpcData.pk, + difficulty: difficulty, + height: parseInt(rpcData.h) + }; }; \ No newline at end of file diff --git a/package.json b/package.json index 238b7ff..ea34d1c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cryptoforknote-util", - "version": "9.1.4", + "version": "10.0.3", "main": "cryptoforknote-util", "author": { "name": "LucasJones", @@ -8,16 +8,16 @@ }, "repository": { "type": "git", - "url": "https://github.com/MoneroOcean/node-cryptoforknote-util.git" + "url": "https://github.com/haven-protocol-org/node-cryptoforknote-util.git" }, "dependencies": { - "promise": "*", + "promise": "*", "bindings": "*", - "nan": "^2.0.0", - "bignum": "^0.13.1", - "sha3": "*", + "nan": "^2.14.2", + "bignum": "^0.13.1", + "sha3": "*", "varuint-bitcoin": "^1.0.4", - "bitcoinjs-lib": "git+https://github.com/bitcoinjs/bitcoinjs-lib.git#533d6c2e6d0aa4111f7948b1c12003cf6ef83137" + "bitcoinjs-lib": "git+https://github.com/bitcoinjs/bitcoinjs-lib.git#533d6c2e6d0aa4111f7948b1c12003cf6ef83137" }, "keywords": [ "cryptonight", diff --git a/src/contrib/epee/include/storages/portable_storage.h b/src/contrib/epee/include/storages/portable_storage.h index d0e40d6..523597d 100644 --- a/src/contrib/epee/include/storages/portable_storage.h +++ b/src/contrib/epee/include/storages/portable_storage.h @@ -37,6 +37,7 @@ #include "portable_storage_val_converters.h" #include "span.h" #include "int-util.h" +#include namespace epee { diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 88425b9..e66ee80 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -2,6 +2,7 @@ #define CURRENT_TRANSACTION_VERSION 1 #define OFFSHORE_TRANSACTION_VERSION 3 +#define HF_VERSION_XASSET_FEES_V2 17 enum BLOB_TYPE { BLOB_TYPE_CRYPTONOTE = 0, diff --git a/src/cryptonote_core/cryptonote_basic.h b/src/cryptonote_core/cryptonote_basic.h index 284f1f3..e8a6b41 100644 --- a/src/cryptonote_core/cryptonote_basic.h +++ b/src/cryptonote_core/cryptonote_basic.h @@ -81,6 +81,19 @@ namespace cryptonote crypto::public_key key; }; + struct txout_xasset + { + txout_xasset() { } + txout_xasset(const crypto::public_key &_key, const std::string &_asset_type) : key(_key), asset_type(_asset_type) { } + crypto::public_key key; + std::string asset_type; + + BEGIN_SERIALIZE_OBJECT() + FIELD(key) + FIELD(asset_type) + END_SERIALIZE() + }; + /* inputs */ struct txin_gen @@ -159,9 +172,24 @@ namespace cryptonote END_SERIALIZE() }; - typedef boost::variant txin_v; + struct txin_xasset + { + uint64_t amount; + std::string asset_type; + std::vector key_offsets; + crypto::key_image k_image; // double spending protection - typedef boost::variant txout_target_v; + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(amount) + FIELD(asset_type) + FIELD(key_offsets) + FIELD(k_image) + END_SERIALIZE() + }; + + typedef boost::variant txin_v; + + typedef boost::variant txout_target_v; //typedef std::pair out_t; struct tx_out @@ -321,6 +349,7 @@ namespace cryptonote vin.size() > 0 && vin[0].type() == typeid(txin_to_key) ? boost::get(vin[0]).key_offsets.size() - 1 : vin.size() > 0 && vin[0].type() == typeid(txin_offshore) ? boost::get(vin[0]).key_offsets.size() - 1 : vin.size() > 0 && vin[0].type() == typeid(txin_onshore) ? boost::get(vin[0]).key_offsets.size() - 1 : + vin.size() > 0 && vin[0].type() == typeid(txin_xasset) ? boost::get(vin[0]).key_offsets.size() - 1 : 0); } if (!r || !ar.stream().good()) return false; @@ -372,6 +401,7 @@ namespace cryptonote size_t operator()(const txin_to_key& txin) const {return txin.key_offsets.size();} size_t operator()(const txin_offshore& txin) const {return txin.key_offsets.size();} size_t operator()(const txin_onshore& txin) const {return txin.key_offsets.size();} + size_t operator()(const txin_xasset& txin) const {return txin.key_offsets.size();} }; return boost::apply_visitor(txin_signature_size_visitor(), tx_in); @@ -612,10 +642,12 @@ VARIANT_TAG(binary_archive, cryptonote::txin_to_scripthash, 0x1); VARIANT_TAG(binary_archive, cryptonote::txin_to_key, 0x2); VARIANT_TAG(binary_archive, cryptonote::txin_offshore, 0x3); VARIANT_TAG(binary_archive, cryptonote::txin_onshore, 0x4); +VARIANT_TAG(binary_archive, cryptonote::txin_xasset, 0x5); VARIANT_TAG(binary_archive, cryptonote::txout_to_script, 0x0); VARIANT_TAG(binary_archive, cryptonote::txout_to_scripthash, 0x1); VARIANT_TAG(binary_archive, cryptonote::txout_to_key, 0x2); VARIANT_TAG(binary_archive, cryptonote::txout_offshore, 0x3); +VARIANT_TAG(binary_archive, cryptonote::txout_xasset, 0x5); VARIANT_TAG(binary_archive, cryptonote::transaction, 0xcc); VARIANT_TAG(binary_archive, cryptonote::block, 0xbb); @@ -625,10 +657,12 @@ VARIANT_TAG(json_archive, cryptonote::txin_to_scripthash, "scripthash"); VARIANT_TAG(json_archive, cryptonote::txin_to_key, "key"); VARIANT_TAG(json_archive, cryptonote::txin_offshore, "offshore"); VARIANT_TAG(json_archive, cryptonote::txin_onshore, "onshore"); +VARIANT_TAG(json_archive, cryptonote::txin_xasset, "xasset"); VARIANT_TAG(json_archive, cryptonote::txout_to_script, "script"); VARIANT_TAG(json_archive, cryptonote::txout_to_scripthash, "scripthash"); VARIANT_TAG(json_archive, cryptonote::txout_to_key, "key"); VARIANT_TAG(json_archive, cryptonote::txout_offshore, "offshore"); +VARIANT_TAG(json_archive, cryptonote::txout_xasset, "xasset"); VARIANT_TAG(json_archive, cryptonote::transaction, "tx"); VARIANT_TAG(json_archive, cryptonote::block, "block"); @@ -638,9 +672,11 @@ VARIANT_TAG(debug_archive, cryptonote::txin_to_scripthash, "scripthash"); VARIANT_TAG(debug_archive, cryptonote::txin_to_key, "key"); VARIANT_TAG(debug_archive, cryptonote::txin_offshore, "offshore"); VARIANT_TAG(debug_archive, cryptonote::txin_onshore, "onshore"); +VARIANT_TAG(debug_archive, cryptonote::txin_xasset, "xasset"); VARIANT_TAG(debug_archive, cryptonote::txout_to_script, "script"); VARIANT_TAG(debug_archive, cryptonote::txout_to_scripthash, "scripthash"); VARIANT_TAG(debug_archive, cryptonote::txout_to_key, "key"); VARIANT_TAG(debug_archive, cryptonote::txout_offshore, "offshore"); +VARIANT_TAG(debug_archive, cryptonote::txout_xasset, "xasset"); VARIANT_TAG(debug_archive, cryptonote::transaction, "tx"); VARIANT_TAG(debug_archive, cryptonote::block, "block"); diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 769a743..ed19b39 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -85,14 +85,24 @@ namespace cryptonote { uint64_t amount_in = 0; uint64_t amount_out = 0; + if ((tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV) && (tx.version > 1)) + { + // This is the correct way to get the fee for Haven, because outs may be in different currencies to ins + fee = tx.rct_signatures.txnFee + tx.rct_signatures.txnOffshoreFee; + return true; + } BOOST_FOREACH(auto& in, tx.vin) { if (tx.blob_type != BLOB_TYPE_CRYPTONOTE_XHV) { CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), 0, "unexpected type id in transaction"); amount_in += boost::get(in).amount; } else { - CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key) || in.type() == typeid(txin_offshore) || in.type() == typeid(txin_onshore), 0, "unexpected type id in transaction"); - amount_in += in.type() == typeid(txin_to_key) ? boost::get(in).amount : in.type() == typeid(txin_onshore) ? boost::get(in).amount : boost::get(in).amount; + CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key) || in.type() == typeid(txin_offshore) || in.type() == typeid(txin_onshore) || in.type() == typeid(txin_xasset), 0, "unexpected type id in transaction"); + amount_in += + in.type() == typeid(txin_to_key) ? boost::get(in).amount : + in.type() == typeid(txin_onshore) ? boost::get(in).amount : + in.type() == typeid(txin_offshore) ? boost::get(in).amount : + boost::get(in).amount; } } BOOST_FOREACH(auto& o, tx.vout) @@ -245,9 +255,12 @@ namespace cryptonote << in.type().name() << ", expected " << typeid(txin_to_key).name() << ", in transaction id=" << get_transaction_hash(tx)); } else { - CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key) || in.type() == typeid(txin_offshore) || in.type() == typeid(txin_onshore), false, "wrong variant type: " - << in.type().name() << ", expected " << typeid(txin_to_key).name() << "or " << typeid(txin_onshore).name() - << ", in transaction id=" << get_transaction_hash(tx)); + CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key) || in.type() == typeid(txin_offshore) || in.type() == typeid(txin_onshore) || in.type() == typeid(txin_xasset), false, "wrong variant type: " + << in.type().name() << ", expected " << typeid(txin_to_key).name() + << "or " << typeid(txin_offshore).name() + << "or " << typeid(txin_onshore).name() + << "or " << typeid(txin_xasset).name() + << ", in transaction id=" << get_transaction_hash(tx)); } } return true; @@ -262,10 +275,13 @@ namespace cryptonote << out.target.type().name() << ", expected " << typeid(txout_to_key).name() << ", in transaction id=" << get_transaction_hash(tx)); } else { - CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key) || out.target.type() == typeid(txout_offshore), false, "wrong variant type: " - << out.target.type().name() << ", expected " << typeid(txout_to_key).name() - << "or " << typeid(txout_offshore).name() - << ", in transaction id=" << get_transaction_hash(tx)); + CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key) || + out.target.type() == typeid(txout_offshore) || + out.target.type() == typeid(txout_xasset), false, "wrong variant type: " + << out.target.type().name() << ", expected " << typeid(txout_to_key).name() + << "or " << typeid(txout_offshore).name() + << "or " << typeid(txout_xasset).name() + << ", in transaction id=" << get_transaction_hash(tx)); } if (tx.version == 1) @@ -277,7 +293,9 @@ namespace cryptonote if(!check_key(boost::get(out.target).key)) return false; } else { - if(!check_key(out.target.type() == typeid(txout_to_key) ? boost::get(out.target).key : boost::get(out.target).key)) + if(!check_key(out.target.type() == typeid(txout_to_key) ? boost::get(out.target).key : + out.target.type() == typeid(txout_offshore) ? boost::get(out.target).key : + boost::get(out.target).key)) return false; } } @@ -294,7 +312,12 @@ namespace cryptonote uint64_t money = 0; BOOST_FOREACH(const auto& in, tx.vin) { - if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV && tx.vin[0].type() == typeid(txin_offshore)) { + if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV && tx.vin[0].type() == typeid(txin_xasset)) { + CHECKED_GET_SPECIFIC_VARIANT(in, const txin_xasset, tokey_in, false); + if(money > tokey_in.amount + money) + return false; + money += tokey_in.amount; + } else if (tx.blob_type == BLOB_TYPE_CRYPTONOTE_XHV && tx.vin[0].type() == typeid(txin_offshore)) { CHECKED_GET_SPECIFIC_VARIANT(in, const txin_offshore, tokey_in, false); if(money > tokey_in.amount + money) return false; @@ -325,6 +348,7 @@ namespace cryptonote } return true; } + /* //--------------------------------------------------------------- uint64_t get_outs_money_amount(const transaction& tx) { @@ -333,6 +357,25 @@ namespace cryptonote outputs_amount += o.amount; return outputs_amount; } + */ + //--------------------------------------------------------------- + std::map get_outs_money_amount(const transaction& tx) + { + std::map outputs_amount; + for(const auto& o: tx.vout) { + std::string asset_type; + if (o.target.type() == typeid(txout_offshore)) { + asset_type = "XUSD"; + } else if (o.target.type() == typeid(txout_xasset)) {; + asset_type = boost::get(o.target).asset_type; + } else { + // this close covers miner tx and normal XHV ouputs. + asset_type = "XHV"; + } + outputs_amount[asset_type] += o.amount; + } + return outputs_amount; + } //--------------------------------------------------------------- std::string short_hash_str(const crypto::hash& h) { @@ -451,6 +494,7 @@ namespace cryptonote t.vin[0].type() == typeid(txin_to_key) ? boost::get(t.vin[0]).key_offsets.size() - 1 : t.vin[0].type() == typeid(txin_offshore) ? boost::get(t.vin[0]).key_offsets.size() - 1 : t.vin[0].type() == typeid(txin_onshore) ? boost::get(t.vin[0]).key_offsets.size() - 1 : + t.vin[0].type() == typeid(txin_xasset) ? boost::get(t.vin[0]).key_offsets.size() - 1 : 0; } bool r = tt.rct_signatures.p.serialize_rctsig_prunable(ba, t.rct_signatures.type, inputs, outputs, mixin); diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index a2ed58a..fb49065 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -85,7 +85,8 @@ namespace cryptonote bool get_bytecoin_block_longhash(const block& blk, crypto::hash& res); bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b); bool get_inputs_money_amount(const transaction& tx, uint64_t& money); - uint64_t get_outs_money_amount(const transaction& tx); + //uint64_t get_outs_money_amount(const transaction& tx); + std::map get_outs_money_amount(const transaction& tx); bool check_inputs_types_supported(const transaction& tx); bool check_outs_valid(const transaction& tx); diff --git a/src/cryptonote_core/tx_extra.h b/src/cryptonote_core/tx_extra.h index 2fba072..6c3843a 100644 --- a/src/cryptonote_core/tx_extra.h +++ b/src/cryptonote_core/tx_extra.h @@ -32,12 +32,16 @@ #define TX_EXTRA_PADDING_MAX_COUNT 255 #define TX_EXTRA_NONCE_MAX_COUNT 255 +#define TX_EXTRA_OFFSHORE_MAX_COUNT 255 +#define TX_EXTRA_MEMO_MAX_COUNT 255 #define TX_EXTRA_TAG_PADDING 0x00 #define TX_EXTRA_TAG_PUBKEY 0x01 #define TX_EXTRA_NONCE 0x02 #define TX_EXTRA_MERGE_MINING_TAG 0x03 #define TX_EXTRA_TAG_ADDITIONAL_PUBKEYS 0x04 +#define TX_EXTRA_TAG_OFFSHORE 0x17 +#define TX_EXTRA_TAG_MEMO 0x18 #define TX_EXTRA_TAG_SERVICE_NODE_REGISTER 0x70 #define TX_EXTRA_TAG_SERVICE_NODE_DEREGISTER 0x71 #define TX_EXTRA_TAG_SERVICE_NODE_WINNER 0x72 @@ -186,6 +190,25 @@ namespace cryptonote END_SERIALIZE() }; + struct tx_extra_offshore + { + std::string data; + + BEGIN_SERIALIZE() + FIELD(data) + END_SERIALIZE() + }; + + struct tx_extra_memo + { + // Actual memo data as string + std::string data; + + BEGIN_SERIALIZE() + FIELD(data) + END_SERIALIZE() + }; + struct tx_extra_service_node_winner { crypto::public_key m_service_node_key; @@ -301,6 +324,8 @@ namespace cryptonote tx_extra_merge_mining_tag, tx_extra_additional_pub_keys, tx_extra_mysterious_minergate, + tx_extra_offshore, + tx_extra_memo, tx_extra_service_node_pubkey, tx_extra_service_node_register, tx_extra_service_node_contributor, @@ -321,6 +346,8 @@ VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EX VARIANT_TAG(binary_archive, cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG); VARIANT_TAG(binary_archive, cryptonote::tx_extra_additional_pub_keys, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS); VARIANT_TAG(binary_archive, cryptonote::tx_extra_mysterious_minergate, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG); +VARIANT_TAG(binary_archive, cryptonote::tx_extra_offshore, TX_EXTRA_TAG_OFFSHORE); +VARIANT_TAG(binary_archive, cryptonote::tx_extra_memo, TX_EXTRA_TAG_MEMO); VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_register, TX_EXTRA_TAG_SERVICE_NODE_REGISTER); VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_deregister, TX_EXTRA_TAG_SERVICE_NODE_DEREGISTER); VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_contributor, TX_EXTRA_TAG_SERVICE_NODE_CONTRIBUTOR); diff --git a/src/offshore/asset_types.h b/src/offshore/asset_types.h new file mode 100644 index 0000000..e179d54 --- /dev/null +++ b/src/offshore/asset_types.h @@ -0,0 +1,143 @@ +// Copyright (c) 2021, 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. + +#pragma once +#include +#include + +namespace offshore { + + const std::vector ASSET_TYPES = {"XHV", "XAG", "XAU", "XAUD", "XBTC", "XCAD", "XCHF", "XCNY", "XEUR", "XGBP", "XJPY", "XNOK", "XNZD", "XUSD"}; + + class asset_type_counts + { + + public: + + // Fields + uint64_t XHV; + uint64_t XAG; + uint64_t XAU; + uint64_t XAUD; + uint64_t XBTC; + uint64_t XCAD; + uint64_t XCHF; + uint64_t XCNY; + uint64_t XEUR; + uint64_t XGBP; + uint64_t XJPY; + uint64_t XNOK; + uint64_t XNZD; + uint64_t XUSD; + + asset_type_counts() noexcept + : XHV(0) + , XAG(0) + , XAU(0) + , XAUD(0) + , XBTC(0) + , XCAD(0) + , XCHF(0) + , XCNY(0) + , XEUR(0) + , XGBP(0) + , XJPY(0) + , XNOK(0) + , XNZD(0) + , XUSD(0) + { + } + + uint64_t operator[](const std::string asset_type) const noexcept + { + if (asset_type == "XHV") { + return XHV; + } else if (asset_type == "XUSD") { + return XUSD; + } else if (asset_type == "XAG") { + return XAG; + } else if (asset_type == "XAU") { + return XAU; + } else if (asset_type == "XAUD") { + return XAUD; + } else if (asset_type == "XBTC") { + return XBTC; + } else if (asset_type == "XCAD") { + return XCAD; + } else if (asset_type == "XCHF") { + return XCHF; + } else if (asset_type == "XCNY") { + return XCNY; + } else if (asset_type == "XEUR") { + return XEUR; + } else if (asset_type == "XGBP") { + return XGBP; + } else if (asset_type == "XJPY") { + return XJPY; + } else if (asset_type == "XNOK") { + return XNOK; + } else if (asset_type == "XNZD") { + return XNZD; + } + + return 0; + } + + void add(const std::string asset_type, const uint64_t val) + { + if (asset_type == "XHV") { + XHV += val; + } else if (asset_type == "XUSD") { + XUSD += val; + } else if (asset_type == "XAG") { + XAG += val; + } else if (asset_type == "XAU") { + XAU += val; + } else if (asset_type == "XAUD") { + XAUD += val; + } else if (asset_type == "XBTC") { + XBTC += val; + } else if (asset_type == "XCAD") { + XCAD += val; + } else if (asset_type == "XCHF") { + XCHF += val; + } else if (asset_type == "XCNY") { + XCNY += val; + } else if (asset_type == "XEUR") { + XEUR += val; + } else if (asset_type == "XGBP") { + XGBP += val; + } else if (asset_type == "XJPY") { + XJPY += val; + } else if (asset_type == "XNOK") { + XNOK += val; + } else if (asset_type == "XNZD") { + XNZD += val; + } + } + }; +} diff --git a/src/offshore/pricing_record.cpp b/src/offshore/pricing_record.cpp index fda0b08..6cf1606 100644 --- a/src/offshore/pricing_record.cpp +++ b/src/offshore/pricing_record.cpp @@ -29,17 +29,6 @@ #include "pricing_record.h" -#include - -#include -#include -#include -#include -#include -#include -#include -#include - #include "serialization/keyvalue_serialization.h" #include "storages/portable_storage.h" @@ -66,6 +55,7 @@ namespace offshore uint64_t unused1; uint64_t unused2; uint64_t unused3; + uint64_t timestamp; std::string signature; BEGIN_KV_SERIALIZE_MAP() @@ -85,6 +75,7 @@ namespace offshore KV_SERIALIZE(unused1) KV_SERIALIZE(unused2) KV_SERIALIZE(unused3) + KV_SERIALIZE(timestamp) KV_SERIALIZE(signature) END_KV_SERIALIZE_MAP() }; @@ -107,6 +98,7 @@ namespace offshore , unused1(0) , unused2(0) , unused3(0) + , timestamp(0) { std::memset(signature, 0, sizeof(signature)); } @@ -133,6 +125,7 @@ namespace offshore unused1 = in.unused1; unused2 = in.unused2; unused3 = in.unused3; + 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); @@ -152,7 +145,7 @@ namespace offshore ss << std::hex << std::setw(2) << std::setfill('0') << (0xff & signature[i]); sig_hex += ss.str(); } - const pr_serialized out{xAG,xAU,xAUD,xBTC,xCAD,xCHF,xCNY,xEUR,xGBP,xJPY,xNOK,xNZD,xUSD,unused1,unused2,unused3,sig_hex}; + const pr_serialized out{xAG,xAU,xAUD,xBTC,xCAD,xCHF,xCNY,xEUR,xGBP,xJPY,xNOK,xNZD,xUSD,unused1,unused2,unused3,timestamp,sig_hex}; return out.store(dest, hparent); } @@ -173,6 +166,7 @@ namespace offshore , unused1(orig.unused1) , unused2(orig.unused2) , unused3(orig.unused3) + , timestamp(orig.timestamp) { std::memcpy(signature, orig.signature, sizeof(signature)); } @@ -195,10 +189,46 @@ namespace offshore unused1 = orig.unused1; unused2 = orig.unused2; unused3 = orig.unused3; + timestamp = orig.timestamp; ::memcpy(signature, orig.signature, sizeof(signature)); return *this; } + uint64_t pricing_record::operator[](const std::string asset_type) const + { + if (asset_type == "XHV") { + return 1000000000000; + } else if (asset_type == "XUSD") { + return unused1; + } else if (asset_type == "XAG") { + return xAG; + } else if (asset_type == "XAU") { + return xAU; + } else if (asset_type == "XAUD") { + return xAUD; + } else if (asset_type == "XBTC") { + return xBTC; + } else if (asset_type == "XCAD") { + return xCAD; + } else if (asset_type == "XCHF") { + return xCHF; + } else if (asset_type == "XCNY") { + return xCNY; + } else if (asset_type == "XEUR") { + return xEUR; + } else if (asset_type == "XGBP") { + return xGBP; + } else if (asset_type == "XJPY") { + return xJPY; + } else if (asset_type == "XNOK") { + return xNOK; + } else if (asset_type == "XNZD") { + return xNZD; + } else { + CHECK_AND_ASSERT_THROW_MES(false, "Asset type doesn't exist in pricing record!"); + } + } + bool pricing_record::equal(const pricing_record& other) const noexcept { return ((xAG == other.xAG) && @@ -217,19 +247,22 @@ namespace offshore (unused1 == other.unused1) && (unused2 == other.unused2) && (unused3 == other.unused3) && + (timestamp == other.timestamp) && !::memcmp(signature, other.signature, sizeof(signature))); } + bool pricing_record::is_empty() const noexcept + { + const pricing_record empty_pr = offshore::pricing_record(); + return (*this).equal(empty_pr); + } - bool pricing_record::verifySignature() const noexcept + bool pricing_record::verifySignature(EVP_PKEY* public_key) const noexcept { // Sanity check - accept empty pricing records - unsigned char test_sig[64]; - std::memset(test_sig, 0, sizeof(test_sig)); - if (std::memcmp(test_sig, signature, sizeof(signature)) == 0) { + if ((*this).is_empty()) return true; - } - + // Convert our internal 64-byte binary representation into 128-byte hex string std::string sig_hex; for (unsigned int i=0; i<64; i++) { @@ -284,6 +317,8 @@ namespace offshore oss << ",\"unused1\":" << unused1; oss << ",\"unused2\":" << unused2; oss << ",\"unused3\":" << unused3; + if (timestamp > 0) + oss << ",\"timestamp\":" << timestamp; oss << "}"; std::string message = oss.str(); @@ -295,19 +330,28 @@ namespace offshore compact += (byte); } - // HERE BE DRAGONS!!! - // NEAC: the public key should be in a file - static const char public_key[] = "-----BEGIN PUBLIC KEY-----\n" - "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5YBxWx1AZCA9jTUk8Pr2uZ9jpfRt\n" - "KWv3Vo1/Gny+1vfaxsXhBQiG1KlHkafNGarzoL0WHW4ocqaaqF5iv8i35A==\n" - "-----END PUBLIC KEY-----\n"; - // LAND AHOY!!! + // Check to see if we have been passed a public key to use + EVP_PKEY* pubkey = NULL; + if (public_key) { + + // Take a copy for local use + pubkey = public_key; + + } else { + + // No public key provided - failover to embedded key + static const char public_key[] = "-----BEGIN PUBLIC KEY-----\n" + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5YBxWx1AZCA9jTUk8Pr2uZ9jpfRt\n" + "KWv3Vo1/Gny+1vfaxsXhBQiG1KlHkafNGarzoL0WHW4ocqaaqF5iv8i35A==\n" + "-----END PUBLIC KEY-----\n"; - // Grab the public key and make it usable - BIO* bio = BIO_new_mem_buf(public_key, (int)sizeof(public_key)); - assert(bio != NULL); - EVP_PKEY* pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); - BIO_free(bio); + BIO* bio = BIO_new_mem_buf(public_key, (int)sizeof(public_key)); + if (!bio) { + return false; + } + pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + BIO_free(bio); + } assert(pubkey != NULL); // Create a verify digest from the message @@ -325,9 +369,12 @@ namespace offshore // Cleanup the context we created EVP_MD_CTX_destroy(ctx); - // Cleanup the openssl stuff - EVP_PKEY_free(pubkey); - + // Was the key provided by the caller? + if (pubkey != public_key) { + // Cleanup the openssl stuff + EVP_PKEY_free(pubkey); + } + if (ret == 1) return true; @@ -336,4 +383,4 @@ namespace offshore return false; } -} \ No newline at end of file +} diff --git a/src/offshore/pricing_record.h b/src/offshore/pricing_record.h index c9f2b46..06a3b18 100644 --- a/src/offshore/pricing_record.h +++ b/src/offshore/pricing_record.h @@ -30,7 +30,18 @@ #pragma once #include "common/pod-class.h" +#include +#include +#include +#include +#include +#include +#include +#include + #include +#include +#include namespace epee { @@ -88,6 +99,7 @@ namespace offshore uint64_t unused1; uint64_t unused2; uint64_t unused3; + uint64_t timestamp; unsigned char signature[64]; // Default c'tor @@ -101,10 +113,14 @@ namespace offshore pricing_record(const pricing_record& orig) noexcept; ~pricing_record() = default; pricing_record& operator=(const pricing_record& orig) noexcept; + + uint64_t operator[](const std::string asset_type) const; bool equal(const pricing_record& other) const noexcept; - bool verifySignature() const noexcept; + bool is_empty() const noexcept; + + bool verifySignature(EVP_PKEY* public_key = NULL) const noexcept; }; inline bool operator==(const pricing_record& a, const pricing_record& b) noexcept @@ -117,4 +133,73 @@ namespace offshore return !a.equal(b); } -} // offshore \ No newline at end of file + // did not have a timestamp + class pricing_record_v1 + { + + public: + uint64_t xAG; + uint64_t xAU; + uint64_t xAUD; + uint64_t xBTC; + uint64_t xCAD; + uint64_t xCHF; + uint64_t xCNY; + uint64_t xEUR; + uint64_t xGBP; + uint64_t xJPY; + uint64_t xNOK; + uint64_t xNZD; + uint64_t xUSD; + uint64_t unused1; + uint64_t unused2; + uint64_t unused3; + unsigned char signature[64]; + + bool write_to_pr(offshore::pricing_record &pr) + { + pr.xAG = xAG; + pr.xAU = xAU; + pr.xAUD = xAUD; + pr.xBTC = xBTC; + pr.xCAD = xCAD; + pr.xCHF = xCHF; + pr.xCNY = xCNY; + pr.xEUR = xEUR; + pr.xGBP = xGBP; + pr.xJPY = xJPY; + pr.xNOK = xNOK; + pr.xNZD = xNZD; + pr.xUSD = xUSD; + pr.unused1 = unused1; + pr.unused2 = unused2; + pr.unused3 = unused3; + pr.timestamp = 0; + ::memcpy(pr.signature, signature, sizeof(pr.signature)); + return true; + }; + + bool read_from_pr(offshore::pricing_record &pr) + { + xAG = pr.xAG; + xAU = pr.xAU; + xAUD = pr.xAUD; + xBTC = pr.xBTC; + xCAD = pr.xCAD; + xCHF = pr.xCHF; + xCNY = pr.xCNY; + xEUR = pr.xEUR; + xGBP = pr.xGBP; + xJPY = pr.xJPY; + xNOK = pr.xNOK; + xNZD = pr.xNZD; + xUSD = pr.xUSD; + unused1 = pr.unused1; + unused2 = pr.unused2; + unused3 = pr.unused3; + ::memcpy(signature, pr.signature, sizeof(signature)); + return true; + }; + }; + +} // offshore diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index 7a29506..0909b0e 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -254,6 +254,7 @@ namespace rct { RCTTypeBulletproof = 3, RCTTypeBulletproof2 = 4, RCTTypeCLSAG = 5, + RCTTypeCLSAGN = 6, }; enum RangeProofType { RangeProofBorromean, RangeProofBulletproof, RangeProofMultiOutputBulletproof, RangeProofPaddedBulletproof }; struct RCTConfig { @@ -269,10 +270,13 @@ namespace rct { std::vector ecdhInfo; ctkeyV outPk; ctkeyV outPk_usd; + ctkeyV outPk_xasset; xmr_amount txnFee; // contains b xmr_amount txnFee_usd; + xmr_amount txnFee_xasset; xmr_amount txnOffshoreFee; xmr_amount txnOffshoreFee_usd; + xmr_amount txnOffshoreFee_xasset; template class Archive> bool serialize_rctsig_base(Archive &ar, size_t inputs, size_t outputs) @@ -280,18 +284,28 @@ namespace rct { FIELD(type) if (type == RCTTypeNull) return ar.stream().good(); - if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG) + if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeCLSAGN) return false; VARINT_FIELD(txnFee) - if (type == RCTTypeCLSAG) + if ((type == RCTTypeCLSAG) || (type == RCTTypeCLSAGN)) { VARINT_FIELD(txnFee_usd) + if (type == RCTTypeCLSAGN) + { + VARINT_FIELD(txnFee_xasset) + } VARINT_FIELD(txnOffshoreFee) VARINT_FIELD(txnOffshoreFee_usd) + if (type == RCTTypeCLSAGN) + { + VARINT_FIELD(txnOffshoreFee_xasset) + } } else { txnFee_usd = 0; + txnFee_xasset = 0; txnOffshoreFee = 0; txnOffshoreFee_usd = 0; + txnOffshoreFee_xasset = 0; } // inputs/outputs not saved, only here for serialization help // FIELD(message) - not serialized, it can be reconstructed @@ -319,7 +333,7 @@ namespace rct { return false; for (size_t i = 0; i < outputs; ++i) { - if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG) + if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeCLSAGN) { ar.begin_object(); if (!typename Archive::is_saving()) @@ -350,21 +364,36 @@ namespace rct { } ar.end_array(); - if (type == RCTTypeCLSAG) + if ((type == RCTTypeCLSAG) || (type == RCTTypeCLSAGN)) { - ar.tag("outPk_usd"); - ar.begin_array(); - PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, outPk_usd); - if (outPk_usd.size() != outputs) - return false; - for (size_t i = 0; i < outputs; ++i) - { - FIELDS(outPk_usd[i].mask) - if (outputs - i > 1) + ar.tag("outPk_usd"); + ar.begin_array(); + PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, outPk_usd); + if (outPk_usd.size() != outputs) + return false; + for (size_t i = 0; i < outputs; ++i) + { + FIELDS(outPk_usd[i].mask) + if (outputs - i > 1) ar.delimit_array(); - } - ar.end_array(); - } + } + ar.end_array(); + } + if (type == RCTTypeCLSAGN) + { + ar.tag("outPk_xasset"); + ar.begin_array(); + PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, outPk_xasset); + if (outPk_xasset.size() != outputs) + return false; + for (size_t i = 0; i < outputs; ++i) + { + FIELDS(outPk_xasset[i].mask) + if (outputs - i > 1) + ar.delimit_array(); + } + ar.end_array(); + } return ar.stream().good(); } @@ -382,12 +411,12 @@ namespace rct { { if (type == RCTTypeNull) return ar.stream().good(); - if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG) + if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeCLSAGN) return false; - if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG) + if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeCLSAGN) { uint32_t nbp = bulletproofs.size(); - if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG) + if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeCLSAGN) VARINT_FIELD(nbp) else FIELD(nbp) @@ -422,7 +451,7 @@ namespace rct { ar.end_array(); } - if (type == RCTTypeCLSAG) + if ((type == RCTTypeCLSAG) || (type == RCTTypeCLSAGN)) { ar.tag("CLSAGs"); ar.begin_array(); @@ -513,7 +542,7 @@ namespace rct { } ar.end_array(); } - if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG) + if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeCLSAGN) { ar.tag("pseudoOuts"); ar.begin_array(); @@ -537,12 +566,12 @@ namespace rct { keyV& get_pseudo_outs() { - return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG ? p.pseudoOuts : pseudoOuts; + return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeCLSAGN ? p.pseudoOuts : pseudoOuts; } keyV const& get_pseudo_outs() const { - return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG ? p.pseudoOuts : pseudoOuts; + return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeCLSAGN ? p.pseudoOuts : pseudoOuts; } }; diff --git a/src/serialization/pricing_record.h b/src/serialization/pricing_record.h index 73d2fb9..2b01f04 100644 --- a/src/serialization/pricing_record.h +++ b/src/serialization/pricing_record.h @@ -35,33 +35,63 @@ #include "serialization.h" #include "debug_archive.h" #include "offshore/pricing_record.h" +#include "cryptonote_config.h" -/* // read template