danicoin/tests/core_tests/TransactionBuilder.cpp
2014-08-13 15:07:19 +01:00

187 lines
5.7 KiB
C++

// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
//
// This file is part of Bytecoin.
//
// Bytecoin is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Bytecoin is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
#include "TransactionBuilder.h"
using namespace cryptonote;
TransactionBuilder::TransactionBuilder(const cryptonote::Currency& currency, uint64_t unlockTime)
: m_currency(currency), m_version(cryptonote::CURRENT_TRANSACTION_VERSION), m_unlockTime(unlockTime), m_txKey(KeyPair::generate()) {}
TransactionBuilder& TransactionBuilder::newTxKeys() {
m_txKey = KeyPair::generate();
return *this;
}
TransactionBuilder& TransactionBuilder::setInput(const std::vector<cryptonote::tx_source_entry>& sources, const cryptonote::account_keys& senderKeys) {
m_sources = sources;
m_senderKeys = senderKeys;
return *this;
}
TransactionBuilder& TransactionBuilder::addMultisignatureInput(const cryptonote::TransactionInputMultisignature& input, const TransactionBuilder::KeysVector& keys) {
MultisignatureSource src;
src.input = input;
src.keys = keys;
m_msigSources.push_back(src);
return *this;
}
TransactionBuilder& TransactionBuilder::setOutput(const std::vector<cryptonote::tx_destination_entry>& destinations) {
m_destinations = destinations;
return *this;
}
TransactionBuilder& TransactionBuilder::addOutput(const cryptonote::tx_destination_entry& dest) {
m_destinations.push_back(dest);
return *this;
}
TransactionBuilder& TransactionBuilder::addMultisignatureOut(uint64_t amount, const KeysVector& keys, uint32_t required) {
cryptonote::TransactionOutputMultisignature target;
for (const auto& key : keys) {
target.keys.push_back(key.m_account_address.m_spendPublicKey);
}
target.requiredSignatures = required;
MultisignatureDestination dst;
dst.amount = amount;
dst.output = target;
m_msigDestinations.push_back(dst);
return *this;
}
Transaction TransactionBuilder::build() const {
crypto::hash prefixHash;
Transaction tx;
add_tx_pub_key_to_extra(tx, m_txKey.pub);
tx.version = m_version;
tx.unlockTime = m_unlockTime;
std::vector<cryptonote::KeyPair> contexts;
fillInputs(tx, contexts);
fillOutputs(tx);
get_transaction_prefix_hash(tx, prefixHash);
signSources(prefixHash, contexts, tx);
return tx;
}
void TransactionBuilder::fillInputs(Transaction& tx, std::vector<cryptonote::KeyPair>& contexts) const {
for (const tx_source_entry& src_entr : m_sources) {
contexts.push_back(KeyPair());
KeyPair& in_ephemeral = contexts.back();
crypto::key_image img;
generate_key_image_helper(m_senderKeys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_ephemeral, img);
// put key image into tx input
TransactionInputToKey input_to_key;
input_to_key.amount = src_entr.amount;
input_to_key.keyImage = img;
// fill outputs array and use relative offsets
for (const tx_source_entry::output_entry& out_entry : src_entr.outputs) {
input_to_key.keyOffsets.push_back(out_entry.first);
}
input_to_key.keyOffsets = absolute_output_offsets_to_relative(input_to_key.keyOffsets);
tx.vin.push_back(input_to_key);
}
for (const auto& msrc : m_msigSources) {
tx.vin.push_back(msrc.input);
}
}
void TransactionBuilder::fillOutputs(Transaction& tx) const {
size_t output_index = 0;
for(const auto& dst_entr : m_destinations) {
crypto::key_derivation derivation;
crypto::public_key out_eph_public_key;
crypto::generate_key_derivation(dst_entr.addr.m_viewPublicKey, m_txKey.sec, derivation);
crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spendPublicKey, out_eph_public_key);
TransactionOutput out;
out.amount = dst_entr.amount;
TransactionOutputToKey tk;
tk.key = out_eph_public_key;
out.target = tk;
tx.vout.push_back(out);
output_index++;
}
for (const auto& mdst : m_msigDestinations) {
TransactionOutput out;
out.amount = mdst.amount;
out.target = mdst.output;
tx.vout.push_back(out);
}
}
void TransactionBuilder::signSources(const crypto::hash& prefixHash, const std::vector<cryptonote::KeyPair>& contexts, Transaction& tx) const {
tx.signatures.clear();
size_t i = 0;
// sign TransactionInputToKey sources
for (const auto& src_entr : m_sources) {
std::vector<const crypto::public_key*> keys_ptrs;
for (const auto& o : src_entr.outputs) {
keys_ptrs.push_back(&o.second);
}
tx.signatures.push_back(std::vector<crypto::signature>());
std::vector<crypto::signature>& sigs = tx.signatures.back();
sigs.resize(src_entr.outputs.size());
generate_ring_signature(prefixHash, boost::get<TransactionInputToKey>(tx.vin[i]).keyImage, keys_ptrs, contexts[i].sec, src_entr.real_output, sigs.data());
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) {
const auto& pk = key.m_account_address.m_spendPublicKey;
const auto& sk = key.m_spend_secret_key;
crypto::signature sig;
crypto::generate_signature(prefixHash, pk, sk, sig);
outsigs.push_back(sig);
}
}
}