TransactionBuilder: Add support for transparent inputs and outputs

This commit is contained in:
Jack Grigg
2018-07-30 11:03:29 +01:00
parent 3fd0a269e1
commit 3466b4677e
3 changed files with 184 additions and 11 deletions

View File

@@ -5,7 +5,8 @@
#include "transaction_builder.h"
#include "main.h"
#include "script/script.h"
#include "pubkey.h"
#include "script/sign.h"
#include <boost/variant.hpp>
#include <librustzcash.h>
@@ -21,7 +22,8 @@ SpendDescriptionInfo::SpendDescriptionInfo(
TransactionBuilder::TransactionBuilder(
const Consensus::Params& consensusParams,
int nHeight) : consensusParams(consensusParams), nHeight(nHeight)
int nHeight,
CKeyStore* keystore) : consensusParams(consensusParams), nHeight(nHeight), keystore(keystore)
{
mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight);
}
@@ -55,8 +57,55 @@ void TransactionBuilder::AddSaplingOutput(
mtx.valueBalance -= value;
}
void TransactionBuilder::AddTransparentInput(COutPoint utxo, CScript scriptPubKey, CAmount value)
{
if (keystore == nullptr) {
throw std::runtime_error("Cannot add transparent inputs to a TransactionBuilder without a keystore");
}
mtx.vin.emplace_back(utxo);
tIns.emplace_back(scriptPubKey, value);
}
bool TransactionBuilder::AddTransparentOutput(CTxDestination& to, CAmount value)
{
if (!IsValidDestination(to)) {
return false;
}
CScript scriptPubKey = GetScriptForDestination(to);
CTxOut out(value, scriptPubKey);
mtx.vout.push_back(out);
return true;
}
boost::optional<CTransaction> TransactionBuilder::Build()
{
// Fixed fee
const CAmount fee = 10000;
//
// Consistency checks
//
// Valid change
CAmount change = mtx.valueBalance - fee;
for (auto tIn : tIns) {
change += tIn.value;
}
for (auto tOut : mtx.vout) {
change -= tOut.nValue;
}
if (change < 0) {
return boost::none;
}
// TODO: Create change output (currently, the change is added to the fee)
//
// Sapling spends and outputs
//
auto ctx = librustzcash_sapling_proving_ctx_init();
// Create Sapling SpendDescriptions
@@ -141,7 +190,10 @@ boost::optional<CTransaction> TransactionBuilder::Build()
mtx.vShieldedOutput.push_back(odesc);
}
// Calculate SignatureHash
//
// Signatures
//
auto consensusBranchId = CurrentEpochBranchId(nHeight, consensusParams);
// Empty output script.
@@ -169,5 +221,23 @@ boost::optional<CTransaction> TransactionBuilder::Build()
mtx.bindingSig.data());
librustzcash_sapling_proving_ctx_free(ctx);
// Transparent signatures
CTransaction txNewConst(mtx);
for (int nIn = 0; nIn < mtx.vin.size(); nIn++) {
auto tIn = tIns[nIn];
SignatureData sigdata;
bool signSuccess = ProduceSignature(
TransactionSignatureCreator(
keystore, &txNewConst, nIn, tIn.value, SIGHASH_ALL),
tIn.scriptPubKey, sigdata, consensusBranchId);
if (!signSuccess) {
return boost::none;
} else {
UpdateTransaction(mtx, nIn, sigdata);
}
}
return CTransaction(mtx);
}