Files

319 lines
12 KiB
C++
Raw Permalink Normal View History

2019-03-11 14:39:38 +01:00
/*
* This file is part of the Flowee project
2024-03-13 17:02:19 +01:00
* Copyright (C) 2019-2024 Tom Zander <tom@flowee.org>
2019-03-11 14:39:38 +01:00
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2024-01-22 19:32:15 +01:00
#ifndef FLOWEE_TRANSACTIONBUILDER_H
#define FLOWEE_TRANSACTIONBUILDER_H
2019-03-11 14:39:38 +01:00
#include "primitives/Tx.h"
2023-11-24 18:16:32 +01:00
#include "primitives/PrivateKey.h"
2020-05-28 22:34:49 +02:00
#include "primitives/script.h"
#include "uint256.h"
2019-03-11 14:39:38 +01:00
2022-07-06 21:56:34 +02:00
class PublicKey;
2020-05-28 22:34:49 +02:00
class CTransaction;
class TransactionBuilderPrivate;
2019-03-12 22:46:31 +01:00
2019-03-11 14:39:38 +01:00
/**
* This class allows anyone to create or extend Bitcoin (BCH) transactions.
*
* A transaction can be started from nothing, or a partially constructed transaction
* can be imported and build further.
*
* Bitcoin transactions are only final once all inputs are signed, which may take
* multiple people signing parts of that transaction. This builder allows building
* new but also importing and extending existing transactions.
*
* TODO when an action destroys an existing signature I should have a way to communicate
* this to the user of this class.
*/
class TransactionBuilder
{
public:
enum SignatureType {
ECDSA,
Schnorr
};
TransactionBuilder();
TransactionBuilder(const Tx &existingTx);
TransactionBuilder(const CTransaction &existingTx);
2020-05-28 22:34:49 +02:00
~TransactionBuilder();
2019-03-11 14:39:38 +01:00
void setFeeTarget(int satsPerKByte);
2019-03-11 14:39:38 +01:00
/**
* Add a new input and select it.
* This uses the default SignAllOutputs SignAllInputs sighash.
*/
int appendInput(const uint256 &txid, int outputIndex);
/**
* Select an input based on index.
* Please note that the first input is numbered as zero (0)
* @returns the input number we selected.
*/
int selectInput(int index);
2020-10-23 22:33:33 +02:00
int outputCount() const;
int inputCount() const;
2019-03-11 14:39:38 +01:00
/// SigHash type, the inputs part.
enum SignInputs {
/**
* This option signs all inputs, making it impossible to combine with other inputs after signing.
*
* This is not directly a signhash type as this is the default behaviour. When in doubt, use this.
*/
SignAllInputs = 0,
/**
* This option allows for full combining of this input with any other inputs, even after signing.
*
* This sighash flag, also called SIGHASH_ANYONECANPAY, is useful to combine different inputs
* from different parties and combine that into a valid transaction.
*
* Be careful about picking an good SignOutputs enum as picking NoOutput will essentially give your
* money to anyone that manages to mine the input first.
*/
SignOnlyThisInput = 0x80,
};
/// SighHash type, the outputs part.
enum SignOutputs {
/**
* An input signed with this will disallow any change in all outputs.
* This sighash type, also called SIGHASH_ALL, signs all outputs, preventing any modification.
*/
SignAllOuputs = 1,
/**
* Put no requirement at all on the outputs to stay the same after signing.
*
* This sighash type, also called SIGHASH_NONE, signs only this input. Best used in
* combination with SignAllInputs because otherwise this input can be combined in another
* transaction and losses can occur.
*/
SignNoOutputs = 2,
/**
* Requires the input to be combined with one specific output.
* This sighash type, also called SIGHASH_SINGLE, signs the output from this transaction
* that has the same index as this input.
*
* Please be aware that if there is no output of the same number that this silently turns
* into a SignNoOutputs.
*
* It allows modifications of other outputs and the sequence number of other inputs.
*/
SignSingleOutput = 3,
};
/**
* Pushes the data needed for the current input to receive its signatures.
2019-03-11 14:39:38 +01:00
*
* Inputs use a signature to prove you own the money that this transaction spends. To make the
2024-09-07 10:34:59 +02:00
* signing secure it doesn't just take the private key, it also takes the prevOutScript and the value
* properties, which your wallet should supply you with.
*
* The SignInputs / SignOutputs options determine how flexible the signature is with regards to a
* changing transaction after final signing time.
*
* For instance a fundraiser may want to combine inputs from a lot of people into one transaction.
* Those inputs can then be signed individually using SignOnlyThisInput and later combined without
* breaking the signature.
*
* A common rule is that outputs or inputs not included in the transaction may be changed after signing
* and before the transaction is mined.
2019-03-11 14:39:38 +01:00
*
* In most cases you should be very careful to pick at least one output you care about that you
* will sign because that guarentees your money can only be spent with those outputs getting paid.
2019-03-11 14:39:38 +01:00
*
* The default is to sign all inputs and all outputs, which implies that the entire transaction
* is fully constructed before signatures are collected.
*
* Notice that actual signing only happens when calling createTransaction()
2019-03-11 14:39:38 +01:00
*/
2024-09-07 10:34:59 +02:00
void pushInputSignature(const PrivateKey &privKey, const CScript &prevOutScript, int64_t value, SignatureType type, SignInputs inputs = SignAllInputs, SignOutputs outputs = SignAllOuputs);
2019-03-11 14:39:38 +01:00
/// locking options.
enum LockingOptions {
/**
* No locking applied, transaction can be mined immediately and spent immediately after.
*/
NoLocking,
/**
* A transaction can be banned from mining till a certain block height.
*
* The value passed is the last block height the transaction is not allowed
* to be mined in.
*
* Please be aware that this allows the transaction to be double spend quite easy.
*/
LockMiningOnBlock,
/**
* A transaction can be banned from mining in a block until a certain time.
* The time is set in seconds since unix epoch, the time should only be in the future.
*
* Please be aware that this allows the transaction to be double spend quite easy.
*/
LockMiningOnTime,
/**
* A transaction *input* can be locked from being mined till a certain block height.
*
* This is only really useful in case the output you are spending used OP_CHECKSEQUENCEVERIFY
*/
RelativeSpendingLockOnBlocks,
/**
* A transaction *input* can be locked from being mined untill a certain time.
*
* This is only really useful in case the output you are spending used OP_CHECKSEQUENCEVERIFY
*/
RelativeSpendingLockOnTime
};
#if 0
2019-03-11 14:39:38 +01:00
/**
* Set the locking option on the current input.
*
* Please be aware that usage of the LockFromMiningBlock or LockFromMiningTime options
* are transaction-global options and will effect all outputs in one go.
*/
void setLocking(LockingOptions option, uint32_t value);
#endif
/// delete an input based on index. Updates current input index.
2019-03-11 14:39:38 +01:00
void deleteInput(int index);
/// Appends and selects an output.
2024-09-06 20:42:29 +02:00
/// returns current output index.
2024-09-07 10:34:59 +02:00
int appendOutput(int64_t value);
2019-03-11 14:39:38 +01:00
/// selects an output
2024-09-06 20:42:29 +02:00
/// returns current output index.
2019-03-11 14:39:38 +01:00
int selectOutput(int index);
2020-06-08 18:45:14 +02:00
/// update the output value on the selected output
void setOutputValue(int64_t value);
/**
* Use argument, or current output to take fee from.
* The transaction-fee is the difference between incoming in inputs and outgoing in outputs.
* In order to have the expected amount of fees paid, we should adjust an output to end up
* with the right amount of satoshi's fees paid per kbyte of transaction-size.
*
* This passes in the output to use, or with the default argument it uses the current selected output.
* Setting the index to a not existing output index will disable the fee adjustment feature.
*/
void setOutputFeeSource(int outputIndex = -1);
2019-03-11 14:39:38 +01:00
/**
* For the selected output a standard output script will be generated
* that sends the funds to the public-key-hash (aka bitcoin-address) passed.
2019-03-11 14:39:38 +01:00
*/
2022-07-06 21:52:47 +02:00
void pushOutputPay2Address(const KeyId &address);
2019-03-11 14:39:38 +01:00
2024-09-06 20:42:29 +02:00
/**
* Set the current output to use the new script.
* See pushOutputPay2Address() and pushOutputPay2Script() for convenience
* versions of this method.
*/
2019-10-09 19:36:29 +02:00
void pushOutputScript(const CScript &script);
2024-09-06 20:42:29 +02:00
/**
* For the selected output a standard output script will be generated
* that sends the funds to the pay to script-hash address passed.
*
* @code
CashAddress::Content c = CashAddress::decodeCashAddrContent(address, "bitcoincash");
if (c.type == CashAddress::SCRIPT_TYPE)
builder.pushOutputPay2Script(c.hash);
* @endcode
*/
void pushOutputPay2Script(const std::vector<uint8_t> &p2SHash);
/**
* For the selected output a standard output script will be generated
* that becomes a prunable (provable unspendable) output based on the OP_RETURN opcode.
*/
void pushOutputNullData(const std::vector<uint8_t> &data);
/// delete an output based on index. Updates current output index.
2019-03-11 14:39:38 +01:00
void deleteOutput(int index);
2024-09-07 10:34:59 +02:00
/**
* For the selected output, start a cashtoken with given category and bitfield.
* Note that if you state a commitment or amount is to be given, you should
* call the pushNftCommitment() or pushOutputFtValue() respectively.
*/
void startOutputToken(const uint256 &category, uint8_t bitfield);
/**
* For the selected output, add commitment data.
* This method throws if you have not started a token, or the bitfield did
* not include a commitment.
2026-05-14 14:40:17 +02:00
* We also throw if the size is larger than 128 bytes.
2024-09-07 10:34:59 +02:00
*/
void pushNftCommitment(const std::vector<uint8_t> &data);
/**
* For the selected output, add the number of fungible tokens this
* output includes.
* This method throws if you have not started a token, or the bitfield did
* not include an amount.
*/
void pushOutputFtAmount(uint64_t amount);
/**
* Remove the token data from the currently selected output.
*/
void clearOutputToken();
/**
* Render the state of the transaction, signing any inputs that we have signing data for.
2022-04-15 17:33:55 +02:00
*
* Inputs that did not explicitly got an pushInputSignature() called will not be signed and
* instead left unchanged.
*
* @see pushInputSignature()
* @see setAnonimize()
*
* @param optional pool to use for memory allocation.
*/
Tx createTransaction(const std::shared_ptr<Streaming::BufferPool> &pool = nullptr) const;
2019-03-11 14:39:38 +01:00
2022-04-15 17:33:55 +02:00
/// return if the transaction created by createTransaction() will be anonimized
bool anonimize() const;
/**
* By turning on the anonimize feature transactions created by createTransaction() will have their
* inputs and outputs sorted according to BIP69, which as the intention that wallet apps and concepts
* like change-address are at least obfuscated in their meaning. This is meant to highten the
* anonimity of the transaction.
*
* See https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki
*/
void setAnonimize(bool on);
2019-03-11 14:39:38 +01:00
2024-03-13 17:02:19 +01:00
/**
* Change the transaction version to \a txVersion.
* The transaction version passed into the builder is used otherwise, or the default (2) if the empty constructor is used.
*/
void setTransactionVersion(int txVersion);
/**
* Returns the transaction version.
*/
int transactionVersion() const;
2019-03-11 14:39:38 +01:00
private:
2022-04-15 17:33:55 +02:00
TransactionBuilder(const TransactionBuilder&) = delete;
TransactionBuilder &operator=(const TransactionBuilder&) = delete;
2020-05-28 22:34:49 +02:00
TransactionBuilderPrivate *d;
2019-03-11 14:39:38 +01:00
};
#endif