diff --git a/doc/release-notes.md b/doc/release-notes.md
index ec71f9456..b5718c45f 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -1,9 +1,5 @@
Bitcoin ABC version 0.17.3 is now available from:
This release includes the following features and fixes:
- - Update fee calculation to add 179 effective bytes per transaction output in excess of inputs.
- Refund 179 bytes worth of minimum fee per input in excess of outputs to a minimum of
- 10 + 34 * (number of utxos)
- - Default minimum relay fee dropped to 250 sat/kb from 1000sat/kb
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 3ad2aece8..64caf58f9 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -1,145 +1,127 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "primitives/transaction.h"
#include "hash.h"
#include "tinyformat.h"
#include "utilstrencodings.h"
std::string COutPoint::ToString() const {
return strprintf("COutPoint(%s, %u)", txid.ToString().substr(0, 10), n);
}
std::string CTxIn::ToString() const {
std::string str;
str += "CTxIn(";
str += prevout.ToString();
if (prevout.IsNull()) {
str += strprintf(", coinbase %s", HexStr(scriptSig));
} else {
str += strprintf(", scriptSig=%s", HexStr(scriptSig).substr(0, 24));
}
if (nSequence != SEQUENCE_FINAL) {
str += strprintf(", nSequence=%u", nSequence);
}
str += ")";
return str;
}
std::string CTxOut::ToString() const {
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)",
nValue.GetSatoshis() / COIN.GetSatoshis(),
nValue.GetSatoshis() % COIN.GetSatoshis(),
HexStr(scriptPubKey).substr(0, 30));
}
CMutableTransaction::CMutableTransaction()
: nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
CMutableTransaction::CMutableTransaction(const CTransaction &tx)
: nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout),
nLockTime(tx.nLockTime) {}
static uint256 ComputeCMutableTransactionHash(const CMutableTransaction &tx) {
return SerializeHash(tx, SER_GETHASH, 0);
}
TxId CMutableTransaction::GetId() const {
return TxId(ComputeCMutableTransactionHash(*this));
}
TxHash CMutableTransaction::GetHash() const {
return TxHash(ComputeCMutableTransactionHash(*this));
}
uint256 CTransaction::ComputeHash() const {
return SerializeHash(*this, SER_GETHASH, 0);
}
/**
* For backward compatibility, the hash is initialized to 0.
* TODO: remove the need for this default constructor entirely.
*/
CTransaction::CTransaction()
: nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0),
hash() {}
CTransaction::CTransaction(const CMutableTransaction &tx)
: nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout),
nLockTime(tx.nLockTime), hash(ComputeHash()) {}
CTransaction::CTransaction(CMutableTransaction &&tx)
: nVersion(tx.nVersion), vin(std::move(tx.vin)), vout(std::move(tx.vout)),
nLockTime(tx.nLockTime), hash(ComputeHash()) {}
Amount CTransaction::GetValueOut() const {
Amount nValueOut(0);
for (std::vector::const_iterator it(vout.begin()); it != vout.end();
++it) {
nValueOut += it->nValue;
if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut))
throw std::runtime_error(std::string(__func__) +
": value out of range");
}
return nValueOut;
}
double CTransaction::ComputePriority(double dPriorityInputs,
unsigned int nTxSize) const {
nTxSize = CalculateModifiedSize(nTxSize);
if (nTxSize == 0) return 0.0;
return dPriorityInputs / nTxSize;
}
unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const {
// In order to avoid disincentivizing cleaning up the UTXO set we don't
// count the constant overhead for each txin and up to 110 bytes of
// scriptSig (which is enough to cover a compressed pubkey p2sh redemption)
// for priority. Providing any more cleanup incentive than making additional
// inputs free would risk encouraging people to create junk outputs to
// redeem later.
if (nTxSize == 0) nTxSize = GetTotalSize();
for (std::vector::const_iterator it(vin.begin()); it != vin.end();
++it) {
unsigned int offset =
41U + std::min(110U, (unsigned int)it->scriptSig.size());
if (nTxSize > offset) nTxSize -= offset;
}
return nTxSize;
}
-size_t CTransaction::GetBillableSize() const {
- size_t nTxSize = GetTotalSize(), inputs = vin.size(), outputs = vout.size();
-
- // 179 bytes is the minimum size it would take to spend any outputs which
- // are created. We want to change in advance of spending them to
- // incentivize keeping your UTXO set reasonbly sized.
- int64_t modSize =
- int64_t(nTxSize) + (int64_t(outputs) - int64_t(inputs)) * 179;
-
- // Note: It is impossible to generate a negative number above in any real
- // world situation. This is because the inputs have a least 179 byte
- // each. However, it is possible to have shorter scriptSigs than 179
- // bytes. Therefore, we include a minimum of 10 bytes + 34 * vouts.
- nTxSize = std::max(int64_t(outputs * 34 + 10), modSize);
-
- return nTxSize;
-}
-
unsigned int CTransaction::GetTotalSize() const {
return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
}
std::string CTransaction::ToString() const {
std::string str;
str += strprintf("CTransaction(txid=%s, ver=%d, vin.size=%u, vout.size=%u, "
"nLockTime=%u)\n",
GetId().ToString().substr(0, 10), nVersion, vin.size(),
vout.size(), nLockTime);
for (unsigned int i = 0; i < vin.size(); i++)
str += " " + vin[i].ToString() + "\n";
for (unsigned int i = 0; i < vout.size(); i++)
str += " " + vout[i].ToString() + "\n";
return str;
}
\ No newline at end of file
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 320232223..27231bcf2 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -1,403 +1,399 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_PRIMITIVES_TRANSACTION_H
#define BITCOIN_PRIMITIVES_TRANSACTION_H
#include "amount.h"
#include "script/script.h"
#include "serialize.h"
#include "uint256.h"
static const int SERIALIZE_TRANSACTION = 0x00;
/**
* A TxId is the identifier of a transaction. Currently identical to TxHash but
* differentiated for type safety.
*/
struct TxId : public uint256 {
TxId() {}
explicit TxId(const uint256 &b) : uint256(b) {}
};
/**
* A TxHash is the double sha256 hash of the full transaction data.
*/
struct TxHash : public uint256 {
explicit TxHash(const uint256 &b) : uint256(b) {}
};
/**
* An outpoint - a combination of a transaction hash and an index n into its
* vout.
*/
class COutPoint {
private:
TxId txid;
uint32_t n;
public:
COutPoint() : txid(), n(-1) {}
COutPoint(uint256 txidIn, uint32_t nIn) : txid(TxId(txidIn)), n(nIn) {}
ADD_SERIALIZE_METHODS;
template
inline void SerializationOp(Stream &s, Operation ser_action) {
READWRITE(txid);
READWRITE(n);
}
bool IsNull() const { return txid.IsNull() && n == uint32_t(-1); }
const TxId &GetTxId() const { return txid; }
uint32_t GetN() const { return n; }
friend bool operator<(const COutPoint &a, const COutPoint &b) {
int cmp = a.txid.Compare(b.txid);
return cmp < 0 || (cmp == 0 && a.n < b.n);
}
friend bool operator==(const COutPoint &a, const COutPoint &b) {
return (a.txid == b.txid && a.n == b.n);
}
friend bool operator!=(const COutPoint &a, const COutPoint &b) {
return !(a == b);
}
std::string ToString() const;
};
/**
* An input of a transaction. It contains the location of the previous
* transaction's output that it claims and a signature that matches the output's
* public key.
*/
class CTxIn {
public:
COutPoint prevout;
CScript scriptSig;
uint32_t nSequence;
/**
* Setting nSequence to this value for every input in a transaction disables
* nLockTime.
*/
static const uint32_t SEQUENCE_FINAL = 0xffffffff;
/* Below flags apply in the context of BIP 68*/
/**
* If this flag set, CTxIn::nSequence is NOT interpreted as a relative
* lock-time.
*/
static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31);
/**
* If CTxIn::nSequence encodes a relative lock-time and this flag is set,
* the relative lock-time has units of 512 seconds, otherwise it specifies
* blocks with a granularity of 1.
*/
static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22);
/**
* If CTxIn::nSequence encodes a relative lock-time, this mask is applied to
* extract that lock-time from the sequence field.
*/
static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff;
/**
* In order to use the same number of bits to encode roughly the same
* wall-clock duration, and because blocks are naturally limited to occur
* every 600s on average, the minimum granularity for time-based relative
* lock-time is fixed at 512 seconds. Converting from CTxIn::nSequence to
* seconds is performed by multiplying by 512 = 2^9, or equivalently
* shifting up by 9 bits.
*/
static const int SEQUENCE_LOCKTIME_GRANULARITY = 9;
CTxIn() { nSequence = SEQUENCE_FINAL; }
explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn = CScript(),
uint32_t nSequenceIn = SEQUENCE_FINAL)
: prevout(prevoutIn), scriptSig(scriptSigIn), nSequence(nSequenceIn) {}
CTxIn(TxId prevTxId, uint32_t nOut, CScript scriptSigIn = CScript(),
uint32_t nSequenceIn = SEQUENCE_FINAL)
: CTxIn(COutPoint(prevTxId, nOut), scriptSigIn, nSequenceIn) {}
ADD_SERIALIZE_METHODS;
template
inline void SerializationOp(Stream &s, Operation ser_action) {
READWRITE(prevout);
READWRITE(scriptSig);
READWRITE(nSequence);
}
friend bool operator==(const CTxIn &a, const CTxIn &b) {
return (a.prevout == b.prevout && a.scriptSig == b.scriptSig &&
a.nSequence == b.nSequence);
}
friend bool operator!=(const CTxIn &a, const CTxIn &b) { return !(a == b); }
std::string ToString() const;
};
/**
* An output of a transaction. It contains the public key that the next input
* must be able to sign with to claim it.
*/
class CTxOut {
public:
Amount nValue;
CScript scriptPubKey;
CTxOut() { SetNull(); }
CTxOut(Amount nValueIn, CScript scriptPubKeyIn)
: nValue(nValueIn), scriptPubKey(scriptPubKeyIn) {}
ADD_SERIALIZE_METHODS;
template
inline void SerializationOp(Stream &s, Operation ser_action) {
READWRITE(nValue);
READWRITE(scriptPubKey);
}
void SetNull() {
nValue = Amount(-1);
scriptPubKey.clear();
}
bool IsNull() const { return (nValue == Amount(-1)); }
Amount GetDustThreshold(const CFeeRate &minRelayTxFee) const {
/**
* "Dust" is defined in terms of CTransaction::minRelayTxFee, which has
* units satoshis-per-kilobyte. If you'd pay more than 1/3 in fees to
* spend something, then we consider it dust. A typical spendable
* non-segwit txout is 34 bytes big, and will need a CTxIn of at least
* 148 bytes to spend: so dust is a spendable txout less than
* 546*minRelayTxFee/1000 (in satoshis). A typical spendable segwit
* txout is 31 bytes big, and will need a CTxIn of at least 67 bytes to
* spend: so dust is a spendable txout less than 294*minRelayTxFee/1000
* (in satoshis).
*/
if (scriptPubKey.IsUnspendable()) return Amount(0);
size_t nSize = GetSerializeSize(*this, SER_DISK, 0);
// the 148 mentioned above
nSize += (32 + 4 + 1 + 107 + 4);
return 3 * minRelayTxFee.GetFee(nSize);
}
bool IsDust(const CFeeRate &minRelayTxFee) const {
return (nValue < GetDustThreshold(minRelayTxFee));
}
friend bool operator==(const CTxOut &a, const CTxOut &b) {
return (a.nValue == b.nValue && a.scriptPubKey == b.scriptPubKey);
}
friend bool operator!=(const CTxOut &a, const CTxOut &b) {
return !(a == b);
}
std::string ToString() const;
};
class CMutableTransaction;
/**
* Basic transaction serialization format:
* - int32_t nVersion
* - std::vector vin
* - std::vector vout
* - uint32_t nLockTime
*/
template
inline void UnserializeTransaction(TxType &tx, Stream &s) {
s >> tx.nVersion;
tx.vin.clear();
tx.vout.clear();
/* Try to read the vin. In case the dummy is there, this will be read as an
* empty vector. */
s >> tx.vin;
/* We read a non-empty vin. Assume a normal vout follows. */
s >> tx.vout;
s >> tx.nLockTime;
}
template
inline void SerializeTransaction(const TxType &tx, Stream &s) {
s << tx.nVersion;
s << tx.vin;
s << tx.vout;
s << tx.nLockTime;
}
/**
* The basic transaction that is broadcasted on the network and contained in
* blocks. A transaction can contain multiple inputs and outputs.
*/
class CTransaction {
public:
// Default transaction version.
static const int32_t CURRENT_VERSION = 2;
// Changing the default transaction version requires a two step process:
// first adapting relay policy by bumping MAX_STANDARD_VERSION, and then
// later date bumping the default CURRENT_VERSION at which point both
// CURRENT_VERSION and MAX_STANDARD_VERSION will be equal.
static const int32_t MAX_STANDARD_VERSION = 2;
// The local variables are made const to prevent unintended modification
// without updating the cached hash value. However, CTransaction is not
// actually immutable; deserialization and assignment are implemented,
// and bypass the constness. This is safe, as they update the entire
// structure, including the hash.
const int32_t nVersion;
const std::vector vin;
const std::vector vout;
const uint32_t nLockTime;
private:
/** Memory only. */
const uint256 hash;
uint256 ComputeHash() const;
public:
/** Construct a CTransaction that qualifies as IsNull() */
CTransaction();
/** Convert a CMutableTransaction into a CTransaction. */
explicit CTransaction(const CMutableTransaction &tx);
explicit CTransaction(CMutableTransaction &&tx);
template inline void Serialize(Stream &s) const {
SerializeTransaction(*this, s);
}
/**
* This deserializing constructor is provided instead of an Unserialize
* method. Unserialize is not possible, since it would require overwriting
* const fields.
*/
template
CTransaction(deserialize_type, Stream &s)
: CTransaction(CMutableTransaction(deserialize, s)) {}
bool IsNull() const { return vin.empty() && vout.empty(); }
const TxId GetId() const { return TxId(hash); }
const TxHash GetHash() const { return TxHash(hash); }
// Return sum of txouts.
Amount GetValueOut() const;
// GetValueIn() is a method on CCoinsViewCache, because
// inputs must be known to compute value in.
// Compute priority, given priority of inputs and (optionally) tx size
double ComputePriority(double dPriorityInputs,
unsigned int nTxSize = 0) const;
// Compute modified tx size for priority calculation (optionally given tx
// size)
unsigned int CalculateModifiedSize(unsigned int nTxSize = 0) const;
- // Computes an adjusted tx size so that the UTXIs are billed partially
- // upfront.
- size_t GetBillableSize() const;
-
/**
* Get the total transaction size in bytes.
* @return Total transaction size in bytes
*/
unsigned int GetTotalSize() const;
bool IsCoinBase() const {
return (vin.size() == 1 && vin[0].prevout.IsNull());
}
friend bool operator==(const CTransaction &a, const CTransaction &b) {
return a.hash == b.hash;
}
friend bool operator!=(const CTransaction &a, const CTransaction &b) {
return a.hash != b.hash;
}
std::string ToString() const;
};
/**
* A mutable version of CTransaction.
*/
class CMutableTransaction {
public:
int32_t nVersion;
std::vector vin;
std::vector vout;
uint32_t nLockTime;
CMutableTransaction();
CMutableTransaction(const CTransaction &tx);
template inline void Serialize(Stream &s) const {
SerializeTransaction(*this, s);
}
template inline void Unserialize(Stream &s) {
UnserializeTransaction(*this, s);
}
template
CMutableTransaction(deserialize_type, Stream &s) {
Unserialize(s);
}
/**
* Compute the id and hash of this CMutableTransaction. This is computed on
* the fly, as opposed to GetId() and GetHash() in CTransaction, which uses
* a cached result.
*/
TxId GetId() const;
TxHash GetHash() const;
friend bool operator==(const CMutableTransaction &a,
const CMutableTransaction &b) {
return a.GetId() == b.GetId();
}
};
typedef std::shared_ptr CTransactionRef;
static inline CTransactionRef MakeTransactionRef() {
return std::make_shared();
}
template
static inline CTransactionRef MakeTransactionRef(Tx &&txIn) {
return std::make_shared(std::forward(txIn));
}
/** Precompute sighash midstate to avoid quadratic hashing */
struct PrecomputedTransactionData {
uint256 hashPrevouts, hashSequence, hashOutputs;
PrecomputedTransactionData()
: hashPrevouts(), hashSequence(), hashOutputs() {}
PrecomputedTransactionData(const PrecomputedTransactionData &txdata)
: hashPrevouts(txdata.hashPrevouts), hashSequence(txdata.hashSequence),
hashOutputs(txdata.hashOutputs) {}
PrecomputedTransactionData(const CTransaction &tx);
};
#endif // BITCOIN_PRIMITIVES_TRANSACTION_H
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 1a656f3e8..e0ed04d22 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -1,780 +1,760 @@
// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "data/tx_invalid.json.h"
#include "data/tx_valid.json.h"
#include "test/test_bitcoin.h"
#include "checkqueue.h"
#include "clientversion.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "key.h"
#include "keystore.h"
#include "policy/policy.h"
#include "script/script.h"
#include "script/script_error.h"
#include "script/sign.h"
#include "script/standard.h"
#include "test/jsonutil.h"
#include "test/scriptflags.h"
#include "utilstrencodings.h"
#include "validation.h" // For CheckRegularTransaction
#include