danicoin/tests/CoreTests/TransactionBuilder.cpp

187 lines
6 KiB
C++
Raw Normal View History

// 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.
2014-08-13 10:51:37 +00:00
#include "TransactionBuilder.h"
2015-07-30 15:22:07 +00:00
#include "CryptoNoteCore/TransactionExtra.h"
#include "CryptoNoteCore/CryptoNoteTools.h"
2014-08-13 10:51:37 +00:00
2015-05-27 12:08:46 +00:00
using namespace CryptoNote;
2015-07-30 15:22:07 +00:00
using namespace Crypto;
using namespace Common;
2014-08-13 10:51:37 +00:00
2015-05-27 12:08:46 +00:00
TransactionBuilder::TransactionBuilder(const CryptoNote::Currency& currency, uint64_t unlockTime)
2015-07-30 15:22:07 +00:00
: m_currency(currency), m_version(CryptoNote::CURRENT_TRANSACTION_VERSION), m_unlockTime(unlockTime), m_txKey(generateKeyPair()) {}
2014-08-13 10:51:37 +00:00
TransactionBuilder& TransactionBuilder::newTxKeys() {
2015-07-30 15:22:07 +00:00
m_txKey = generateKeyPair();
2014-08-13 10:51:37 +00:00
return *this;
}
2015-05-27 12:08:46 +00:00
TransactionBuilder& TransactionBuilder::setTxKeys(const CryptoNote::KeyPair& txKeys) {
m_txKey = txKeys;
return *this;
}
2014-08-13 10:51:37 +00:00
2015-07-30 15:22:07 +00:00
TransactionBuilder& TransactionBuilder::setInput(const std::vector<CryptoNote::TransactionSourceEntry>& sources, const CryptoNote::AccountKeys& senderKeys) {
2014-08-13 10:51:37 +00:00
m_sources = sources;
m_senderKeys = senderKeys;
return *this;
}
TransactionBuilder& TransactionBuilder::addMultisignatureInput(const MultisignatureSource& source) {
m_msigSources.push_back(source);
2014-08-13 10:51:37 +00:00
return *this;
}
2015-07-30 15:22:07 +00:00
TransactionBuilder& TransactionBuilder::setOutput(const std::vector<CryptoNote::TransactionDestinationEntry>& destinations) {
2014-08-13 10:51:37 +00:00
m_destinations = destinations;
return *this;
}
2015-07-30 15:22:07 +00:00
TransactionBuilder& TransactionBuilder::addOutput(const CryptoNote::TransactionDestinationEntry& dest) {
2014-08-13 10:51:37 +00:00
m_destinations.push_back(dest);
return *this;
}
TransactionBuilder& TransactionBuilder::addMultisignatureOut(uint64_t amount, const KeysVector& keys, uint32_t required) {
MultisignatureDestination dst;
dst.amount = amount;
dst.keys = keys;
dst.requiredSignatures = required;
2014-08-13 10:51:37 +00:00
m_msigDestinations.push_back(dst);
return *this;
}
Transaction TransactionBuilder::build() const {
2015-07-30 15:22:07 +00:00
Crypto::Hash prefixHash;
2014-08-13 10:51:37 +00:00
Transaction tx;
2015-07-30 15:22:07 +00:00
addTransactionPublicKeyToExtra(tx.extra, m_txKey.publicKey);
2014-08-13 10:51:37 +00:00
2015-05-27 12:08:46 +00:00
tx.version = static_cast<uint8_t>(m_version);
2014-08-13 10:51:37 +00:00
tx.unlockTime = m_unlockTime;
2015-05-27 12:08:46 +00:00
std::vector<CryptoNote::KeyPair> contexts;
2014-08-13 10:51:37 +00:00
fillInputs(tx, contexts);
fillOutputs(tx);
2015-07-30 15:22:07 +00:00
getObjectHash(*static_cast<TransactionPrefix*>(&tx), prefixHash);
2014-08-13 10:51:37 +00:00
signSources(prefixHash, contexts, tx);
return tx;
}
2015-05-27 12:08:46 +00:00
void TransactionBuilder::fillInputs(Transaction& tx, std::vector<CryptoNote::KeyPair>& contexts) const {
2015-07-30 15:22:07 +00:00
for (const TransactionSourceEntry& src_entr : m_sources) {
2014-08-13 10:51:37 +00:00
contexts.push_back(KeyPair());
KeyPair& in_ephemeral = contexts.back();
2015-07-30 15:22:07 +00:00
Crypto::KeyImage img;
generate_key_image_helper(m_senderKeys, src_entr.realTransactionPublicKey, src_entr.realOutputIndexInTransaction, in_ephemeral, img);
2014-08-13 10:51:37 +00:00
// put key image into tx input
2015-07-30 15:22:07 +00:00
KeyInput input_to_key;
2014-08-13 10:51:37 +00:00
input_to_key.amount = src_entr.amount;
input_to_key.keyImage = img;
// fill outputs array and use relative offsets
2015-07-30 15:22:07 +00:00
for (const TransactionSourceEntry::OutputEntry& out_entry : src_entr.outputs) {
input_to_key.outputIndexes.push_back(out_entry.first);
2014-08-13 10:51:37 +00:00
}
2015-07-30 15:22:07 +00:00
input_to_key.outputIndexes = absolute_output_offsets_to_relative(input_to_key.outputIndexes);
tx.inputs.push_back(input_to_key);
2014-08-13 10:51:37 +00:00
}
for (const auto& msrc : m_msigSources) {
2015-07-30 15:22:07 +00:00
tx.inputs.push_back(msrc.input);
2014-08-13 10:51:37 +00:00
}
}
void TransactionBuilder::fillOutputs(Transaction& tx) const {
size_t output_index = 0;
for(const auto& dst_entr : m_destinations) {
2015-07-30 15:22:07 +00:00
Crypto::KeyDerivation derivation;
Crypto::PublicKey out_eph_public_key;
Crypto::generate_key_derivation(dst_entr.addr.viewPublicKey, m_txKey.secretKey, derivation);
Crypto::derive_public_key(derivation, output_index, dst_entr.addr.spendPublicKey, out_eph_public_key);
2014-08-13 10:51:37 +00:00
TransactionOutput out;
out.amount = dst_entr.amount;
2015-07-30 15:22:07 +00:00
KeyOutput tk;
2014-08-13 10:51:37 +00:00
tk.key = out_eph_public_key;
out.target = tk;
2015-07-30 15:22:07 +00:00
tx.outputs.push_back(out);
2014-08-13 10:51:37 +00:00
output_index++;
}
for (const auto& mdst : m_msigDestinations) {
2014-08-13 10:51:37 +00:00
TransactionOutput out;
2015-07-30 15:22:07 +00:00
MultisignatureOutput target;
2015-07-30 15:22:07 +00:00
target.requiredSignatureCount = mdst.requiredSignatures;
for (const auto& key : mdst.keys) {
2015-07-30 15:22:07 +00:00
Crypto::KeyDerivation derivation;
Crypto::PublicKey ephemeralPublicKey;
Crypto::generate_key_derivation(key.address.viewPublicKey, m_txKey.secretKey, derivation);
Crypto::derive_public_key(derivation, output_index, key.address.spendPublicKey, ephemeralPublicKey);
target.keys.push_back(ephemeralPublicKey);
}
2014-08-13 10:51:37 +00:00
out.amount = mdst.amount;
out.target = target;
2015-07-30 15:22:07 +00:00
tx.outputs.push_back(out);
output_index++;
2014-08-13 10:51:37 +00:00
}
}
2015-07-30 15:22:07 +00:00
void TransactionBuilder::signSources(const Crypto::Hash& prefixHash, const std::vector<CryptoNote::KeyPair>& contexts, Transaction& tx) const {
2014-08-13 10:51:37 +00:00
tx.signatures.clear();
size_t i = 0;
// sign TransactionInputToKey sources
for (const auto& src_entr : m_sources) {
2015-07-30 15:22:07 +00:00
std::vector<const Crypto::PublicKey*> keys_ptrs;
2014-08-13 10:51:37 +00:00
for (const auto& o : src_entr.outputs) {
keys_ptrs.push_back(&o.second);
}
2015-07-30 15:22:07 +00:00
tx.signatures.push_back(std::vector<Crypto::Signature>());
std::vector<Crypto::Signature>& sigs = tx.signatures.back();
2014-08-13 10:51:37 +00:00
sigs.resize(src_entr.outputs.size());
2015-07-30 15:22:07 +00:00
generate_ring_signature(prefixHash, boost::get<KeyInput>(tx.inputs[i]).keyImage, keys_ptrs, contexts[i].secretKey, src_entr.realOutput, sigs.data());
2014-08-13 10:51:37 +00:00
i++;
}
// sign multisignature source
for (const auto& msrc : m_msigSources) {
tx.signatures.resize(tx.signatures.size() + 1);
auto& outsigs = tx.signatures.back();
for (const auto& key : msrc.keys) {
2015-07-30 15:22:07 +00:00
Crypto::KeyDerivation derivation;
Crypto::PublicKey ephemeralPublicKey;
Crypto::SecretKey ephemeralSecretKey;
2015-07-30 15:22:07 +00:00
Crypto::generate_key_derivation(msrc.srcTxPubKey, key.viewSecretKey, derivation);
Crypto::derive_public_key(derivation, msrc.srcOutputIndex, key.address.spendPublicKey, ephemeralPublicKey);
Crypto::derive_secret_key(derivation, msrc.srcOutputIndex, key.spendSecretKey, ephemeralSecretKey);
2015-07-30 15:22:07 +00:00
Crypto::Signature sig;
Crypto::generate_signature(prefixHash, ephemeralPublicKey, ephemeralSecretKey, sig);
2014-08-13 10:51:37 +00:00
outsigs.push_back(sig);
}
}
}