danicoin/src/CryptoNoteCore/TransactionExtra.cpp
2016-01-18 15:33:29 +00:00

206 lines
5.9 KiB
C++
Executable file

// Copyright (c) 2011-2016 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "TransactionExtra.h"
#include "Common/MemoryInputStream.h"
#include "Common/StreamTools.h"
#include "Common/StringTools.h"
#include "CryptoNoteTools.h"
#include "Serialization/BinaryOutputStreamSerializer.h"
#include "Serialization/BinaryInputStreamSerializer.h"
using namespace Crypto;
using namespace Common;
namespace CryptoNote {
bool parseTransactionExtra(const std::vector<uint8_t> &transactionExtra, std::vector<TransactionExtraField> &transactionExtraFields) {
transactionExtraFields.clear();
if (transactionExtra.empty())
return true;
try {
MemoryInputStream iss(transactionExtra.data(), transactionExtra.size());
BinaryInputStreamSerializer ar(iss);
int c = 0;
while (!iss.endOfStream()) {
c = read<uint8_t>(iss);
switch (c) {
case TX_EXTRA_TAG_PADDING: {
size_t size = 1;
for (; !iss.endOfStream() && size <= TX_EXTRA_PADDING_MAX_COUNT; ++size) {
if (read<uint8_t>(iss) != 0) {
return false; // all bytes should be zero
}
}
if (size > TX_EXTRA_PADDING_MAX_COUNT) {
return false;
}
transactionExtraFields.push_back(TransactionExtraPadding{ size });
break;
}
case TX_EXTRA_TAG_PUBKEY: {
TransactionExtraPublicKey extraPk;
ar(extraPk.publicKey, "public_key");
transactionExtraFields.push_back(extraPk);
break;
}
case TX_EXTRA_NONCE: {
TransactionExtraNonce extraNonce;
uint8_t size = read<uint8_t>(iss);
if (size > 0) {
extraNonce.nonce.resize(size);
read(iss, extraNonce.nonce.data(), extraNonce.nonce.size());
}
transactionExtraFields.push_back(extraNonce);
break;
}
}
}
} catch (std::exception &) {
return false;
}
return true;
}
struct ExtraSerializerVisitor : public boost::static_visitor<bool> {
std::vector<uint8_t>& extra;
ExtraSerializerVisitor(std::vector<uint8_t>& tx_extra)
: extra(tx_extra) {}
bool operator()(const TransactionExtraPadding& t) {
if (t.size > TX_EXTRA_PADDING_MAX_COUNT) {
return false;
}
extra.insert(extra.end(), t.size, 0);
return true;
}
bool operator()(const TransactionExtraPublicKey& t) {
return addTransactionPublicKeyToExtra(extra, t.publicKey);
}
bool operator()(const TransactionExtraNonce& t) {
return addExtraNonceToTransactionExtra(extra, t.nonce);
}
};
bool writeTransactionExtra(std::vector<uint8_t>& tx_extra, const std::vector<TransactionExtraField>& tx_extra_fields) {
ExtraSerializerVisitor visitor(tx_extra);
for (const auto& tag : tx_extra_fields) {
if (!boost::apply_visitor(visitor, tag)) {
return false;
}
}
return true;
}
PublicKey getTransactionPublicKeyFromExtra(const std::vector<uint8_t>& tx_extra) {
std::vector<TransactionExtraField> tx_extra_fields;
parseTransactionExtra(tx_extra, tx_extra_fields);
TransactionExtraPublicKey pub_key_field;
if (!findTransactionExtraFieldByType(tx_extra_fields, pub_key_field))
return boost::value_initialized<PublicKey>();
return pub_key_field.publicKey;
}
bool addTransactionPublicKeyToExtra(std::vector<uint8_t>& tx_extra, const PublicKey& tx_pub_key) {
tx_extra.resize(tx_extra.size() + 1 + sizeof(PublicKey));
tx_extra[tx_extra.size() - 1 - sizeof(PublicKey)] = TX_EXTRA_TAG_PUBKEY;
*reinterpret_cast<PublicKey*>(&tx_extra[tx_extra.size() - sizeof(PublicKey)]) = tx_pub_key;
return true;
}
bool addExtraNonceToTransactionExtra(std::vector<uint8_t>& tx_extra, const BinaryArray& extra_nonce) {
if (extra_nonce.size() > TX_EXTRA_NONCE_MAX_COUNT) {
return false;
}
size_t start_pos = tx_extra.size();
tx_extra.resize(tx_extra.size() + 2 + extra_nonce.size());
//write tag
tx_extra[start_pos] = TX_EXTRA_NONCE;
//write len
++start_pos;
tx_extra[start_pos] = static_cast<uint8_t>(extra_nonce.size());
//write data
++start_pos;
memcpy(&tx_extra[start_pos], extra_nonce.data(), extra_nonce.size());
return true;
}
void setPaymentIdToTransactionExtraNonce(std::vector<uint8_t>& extra_nonce, const Hash& payment_id) {
extra_nonce.clear();
extra_nonce.push_back(TX_EXTRA_NONCE_PAYMENT_ID);
const uint8_t* payment_id_ptr = reinterpret_cast<const uint8_t*>(&payment_id);
std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce));
}
bool getPaymentIdFromTransactionExtraNonce(const std::vector<uint8_t>& extra_nonce, Hash& payment_id) {
if (sizeof(Hash) + 1 != extra_nonce.size())
return false;
if (TX_EXTRA_NONCE_PAYMENT_ID != extra_nonce[0])
return false;
payment_id = *reinterpret_cast<const Hash*>(extra_nonce.data() + 1);
return true;
}
bool parsePaymentId(const std::string& paymentIdString, Hash& paymentId) {
return Common::podFromHex(paymentIdString, paymentId);
}
bool createTxExtraWithPaymentId(const std::string& paymentIdString, std::vector<uint8_t>& extra) {
Hash paymentIdBin;
if (!parsePaymentId(paymentIdString, paymentIdBin)) {
return false;
}
std::vector<uint8_t> extraNonce;
CryptoNote::setPaymentIdToTransactionExtraNonce(extraNonce, paymentIdBin);
if (!CryptoNote::addExtraNonceToTransactionExtra(extra, extraNonce)) {
return false;
}
return true;
}
bool getPaymentIdFromTxExtra(const std::vector<uint8_t>& extra, Hash& paymentId) {
std::vector<TransactionExtraField> tx_extra_fields;
if (!parseTransactionExtra(extra, tx_extra_fields)) {
return false;
}
TransactionExtraNonce extra_nonce;
if (findTransactionExtraFieldByType(tx_extra_fields, extra_nonce)) {
if (!getPaymentIdFromTransactionExtraNonce(extra_nonce.nonce, paymentId)) {
return false;
}
} else {
return false;
}
return true;
}
}