diff --git a/package.json b/package.json index 238b7ff..331169c 100644 --- a/package.json +++ b/package.json @@ -11,13 +11,13 @@ "url": "https://github.com/MoneroOcean/node-cryptoforknote-util.git" }, "dependencies": { - "promise": "*", + "promise": "*", "bindings": "*", - "nan": "^2.0.0", - "bignum": "^0.13.1", - "sha3": "*", + "nan": "^2.0.0", + "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/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/pricing_record.cpp b/src/offshore/pricing_record.cpp index fda0b08..256b601 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" @@ -199,6 +188,41 @@ namespace offshore return *this; } + uint64_t pricing_record::operator[](const std::string asset_type) const noexcept + { + 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 { + return 1000000000000; + } + } + bool pricing_record::equal(const pricing_record& other) const noexcept { return ((xAG == other.xAG) && @@ -221,7 +245,7 @@ namespace offshore } - 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]; @@ -295,19 +319,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 +358,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 +372,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..7115417 100644 --- a/src/offshore/pricing_record.h +++ b/src/offshore/pricing_record.h @@ -30,7 +30,17 @@ #pragma once #include "common/pod-class.h" +#include +#include +#include +#include +#include +#include +#include +#include + #include +#include namespace epee { @@ -101,10 +111,12 @@ 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 noexcept; bool equal(const pricing_record& other) const noexcept; - bool verifySignature() 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 +129,4 @@ namespace offshore return !a.equal(b); } -} // offshore \ No newline at end of file +} // 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; } };