Skip to content

Commit f3bbc74

Browse files
committed
Merge bitcoin/bitcoin#32406: policy: uncap datacarrier by default
a189d63 add release note for datacarriersize default change (Greg Sanders) a141e1b Add more OP_RETURN mempool acceptance functional tests (Peter Todd) 0b4048c datacarrier: deprecate startup arguments for future removal (Greg Sanders) 63091b7 test: remove unnecessary -datacarriersize args from tests (Greg Sanders) 9f36962 policy: uncap datacarrier by default (Greg Sanders) Pull request description: Retains the `-datacarrier*` args, marks them as deprecated, and does not require another startup argument for multiple OP_RETURN outputs. If a user has set `-datacarriersize` the value is "budgeted" across all seen OP_RETURN output scriptPubKeys. In other words the total script bytes stays the same, but can be spread across any number of outputs. This is done to not introduce an additional argument to support multiple outputs. I do not advise people use the option with custom arguments and it is marked as deprecated to not mislead as a promise to offer it forever. The argument itself can be removed in some future release to clean up the code and minimize footguns for users. ACKs for top commit: stickies-v: re-ACK a189d63 Sjors: re-ACK a189d63 polespinasa: re-ACK a189d63 hodlinator: re-ACK a189d63 ajtowns: reACK a189d63 mzumsande: re-ACK a189d63 petertodd: ACK a189d63 theStack: re-ACK a189d63 1440000bytes: re-ACK a189d63 willcl-ark: ACK a189d63 dergoegge: ACK a189d63 fanquake: ACK a189d63 murchandamus: ACK a189d63 darosior: Concept ACK a189d63. Tree-SHA512: 3da2f1ef2f50884d4da7e50df2121bf175cb826edaa14ba7c3068a6d5b2a70beb426edc55d50338ee1d9686b9f74fdf9e10d30fb26a023a718dd82fa1e77b038
2 parents e217437 + a189d63 commit f3bbc74

26 files changed

+146
-94
lines changed

doc/release-notes-32406.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- `-datacarriersize` is increased to 100,000 which effectively uncaps the limit (as the maximum transaction size limit will be hit first). It can be overridden with -datacarriersize=83 to revert to the limit enforced in previous versions. Both `-datacarrier` and `-datacarriersize` options have been marked as deprecated and are expected to be removed in a future release. (#32406)
2+
3+
- Multiple data carrier (OP_RETURN) outputs in a transaction are now permitted for relay and mining. The `-datacarriersize` limit applies to the aggregate size of the scriptPubKeys across all such outputs in a transaction, not including the scriptPubKey size itself. (#32406)

src/init.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -630,10 +630,10 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
630630
argsman.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
631631
argsman.AddArg("-acceptstalefeeestimates", strprintf("Read fee estimates even if they are stale (%sdefault: %u) fee estimates are considered stale if they are %s hours old", "regtest only; ", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES, Ticks<std::chrono::hours>(MAX_FILE_AGE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
632632
argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
633-
argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
633+
argsman.AddArg("-datacarrier", strprintf("(DEPRECATED) Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
634634
argsman.AddArg("-datacarriersize",
635-
strprintf("Relay and mine transactions whose data-carrying raw scriptPubKey "
636-
"is of this size or less (default: %u)",
635+
strprintf("(DEPRECATED) Relay and mine transactions whose data-carrying raw scriptPubKeys in aggregate "
636+
"are of this size or less, allowing multiple outputs (default: %u)",
637637
MAX_OP_RETURN_RELAY),
638638
ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
639639
argsman.AddArg("-permitbaremultisig", strprintf("Relay transactions creating non-P2SH multisig outputs (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY,
@@ -875,6 +875,10 @@ bool AppInitParameterInteraction(const ArgsManager& args)
875875
InitWarning(_("Option '-checkpoints' is set but checkpoints were removed. This option has no effect."));
876876
}
877877

878+
if (args.IsArgSet("-datacarriersize") || args.IsArgSet("-datacarrier")) {
879+
InitWarning(_("Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated. They will be removed in a future version."));
880+
}
881+
878882
// Error if network-specific options (-addnode, -connect, etc) are
879883
// specified in default section of config file, but not overridden
880884
// on the command line or in this chain's section of the config file.

src/policy/policy.cpp

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ std::vector<uint32_t> GetDust(const CTransaction& tx, CFeeRate dust_relay_rate)
7676
return dust_outputs;
7777
}
7878

79-
bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType)
79+
bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType)
8080
{
8181
std::vector<std::vector<unsigned char> > vSolutions;
8282
whichType = Solver(scriptPubKey, vSolutions);
@@ -91,10 +91,6 @@ bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_
9191
return false;
9292
if (m < 1 || m > n)
9393
return false;
94-
} else if (whichType == TxoutType::NULL_DATA) {
95-
if (!max_datacarrier_bytes || scriptPubKey.size() > *max_datacarrier_bytes) {
96-
return false;
97-
}
9894
}
9995

10096
return true;
@@ -137,17 +133,22 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat
137133
}
138134
}
139135

140-
unsigned int nDataOut = 0;
136+
unsigned int datacarrier_bytes_left = max_datacarrier_bytes.value_or(0);
141137
TxoutType whichType;
142138
for (const CTxOut& txout : tx.vout) {
143-
if (!::IsStandard(txout.scriptPubKey, max_datacarrier_bytes, whichType)) {
139+
if (!::IsStandard(txout.scriptPubKey, whichType)) {
144140
reason = "scriptpubkey";
145141
return false;
146142
}
147143

148-
if (whichType == TxoutType::NULL_DATA)
149-
nDataOut++;
150-
else if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) {
144+
if (whichType == TxoutType::NULL_DATA) {
145+
unsigned int size = txout.scriptPubKey.size();
146+
if (size > datacarrier_bytes_left) {
147+
reason = "datacarrier";
148+
return false;
149+
}
150+
datacarrier_bytes_left -= size;
151+
} else if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) {
151152
reason = "bare-multisig";
152153
return false;
153154
}
@@ -159,12 +160,6 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat
159160
return false;
160161
}
161162

162-
// only one OP_RETURN txout is permitted
163-
if (nDataOut > 1) {
164-
reason = "multi-op-return";
165-
return false;
166-
}
167-
168163
return true;
169164
}
170165

src/policy/policy.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,9 @@ static constexpr unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT_KVB{101};
7373
/** Default for -datacarrier */
7474
static const bool DEFAULT_ACCEPT_DATACARRIER = true;
7575
/**
76-
* Default setting for -datacarriersize. 80 bytes of data, +1 for OP_RETURN,
77-
* +2 for the pushdata opcodes.
76+
* Default setting for -datacarriersize in vbytes.
7877
*/
79-
static const unsigned int MAX_OP_RETURN_RELAY = 83;
78+
static const unsigned int MAX_OP_RETURN_RELAY = MAX_STANDARD_TX_WEIGHT / WITNESS_SCALE_FACTOR;
8079
/**
8180
* An extra transaction can be added to a package, as long as it only has one
8281
* ancestor and is no larger than this. Not really any reason to make this
@@ -136,7 +135,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);
136135

137136
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee);
138137

139-
bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType);
138+
bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType);
140139

141140
/** Get the vout index numbers of all dust outputs */
142141
std::vector<uint32_t> GetDust(const CTransaction& tx, CFeeRate dust_relay_rate);

src/test/fuzz/key.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,12 @@ FUZZ_TARGET(key, .init = initialize_key)
150150
assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
151151

152152
TxoutType which_type_tx_pubkey;
153-
const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, std::nullopt, which_type_tx_pubkey);
153+
const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, which_type_tx_pubkey);
154154
assert(is_standard_tx_pubkey);
155155
assert(which_type_tx_pubkey == TxoutType::PUBKEY);
156156

157157
TxoutType which_type_tx_multisig;
158-
const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, std::nullopt, which_type_tx_multisig);
158+
const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, which_type_tx_multisig);
159159
assert(is_standard_tx_multisig);
160160
assert(which_type_tx_multisig == TxoutType::MULTISIG);
161161

src/test/fuzz/script.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ FUZZ_TARGET(script, .init = initialize_script)
5353
}
5454

5555
TxoutType which_type;
56-
bool is_standard_ret = IsStandard(script, std::nullopt, which_type);
56+
bool is_standard_ret = IsStandard(script, which_type);
5757
if (!is_standard_ret) {
5858
assert(which_type == TxoutType::NONSTANDARD ||
5959
which_type == TxoutType::NULL_DATA ||

src/test/multisig_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
144144

145145
const auto is_standard{[](const CScript& spk) {
146146
TxoutType type;
147-
bool res{::IsStandard(spk, std::nullopt, type)};
147+
bool res{::IsStandard(spk, type)};
148148
if (res) {
149149
BOOST_CHECK_EQUAL(type, TxoutType::MULTISIG);
150150
}

src/test/transaction_tests.cpp

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -797,14 +797,14 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
797797
CKey key = GenerateRandomKey();
798798
t.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
799799

800-
constexpr auto CheckIsStandard = [](const auto& t) {
800+
constexpr auto CheckIsStandard = [](const auto& t, const unsigned int max_op_return_relay = MAX_OP_RETURN_RELAY) {
801801
std::string reason;
802-
BOOST_CHECK(IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_multi, g_dust, reason));
802+
BOOST_CHECK(IsStandardTx(CTransaction{t}, max_op_return_relay, g_bare_multi, g_dust, reason));
803803
BOOST_CHECK(reason.empty());
804804
};
805-
constexpr auto CheckIsNotStandard = [](const auto& t, const std::string& reason_in) {
805+
constexpr auto CheckIsNotStandard = [](const auto& t, const std::string& reason_in, const unsigned int max_op_return_relay = MAX_OP_RETURN_RELAY) {
806806
std::string reason;
807-
BOOST_CHECK(!IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_multi, g_dust, reason));
807+
BOOST_CHECK(!IsStandardTx(CTransaction{t}, max_op_return_relay, g_bare_multi, g_dust, reason));
808808
BOOST_CHECK_EQUAL(reason_in, reason);
809809
};
810810

@@ -858,15 +858,13 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
858858
t.vout[0].scriptPubKey = CScript() << OP_1;
859859
CheckIsNotStandard(t, "scriptpubkey");
860860

861-
// MAX_OP_RETURN_RELAY-byte TxoutType::NULL_DATA (standard)
861+
// Custom 83-byte TxoutType::NULL_DATA (standard with max_op_return_relay of 83)
862862
t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
863-
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size());
864-
CheckIsStandard(t);
863+
BOOST_CHECK_EQUAL(83, t.vout[0].scriptPubKey.size());
864+
CheckIsStandard(t, /*max_op_return_relay=*/83);
865865

866-
// MAX_OP_RETURN_RELAY+1-byte TxoutType::NULL_DATA (non-standard)
867-
t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"_hex;
868-
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size());
869-
CheckIsNotStandard(t, "scriptpubkey");
866+
// Non-standard if max_op_return_relay datacarrier arg is one less
867+
CheckIsNotStandard(t, "datacarrier", /*max_op_return_relay=*/82);
870868

871869
// Data payload can be encoded in any way...
872870
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ""_hex;
@@ -888,21 +886,28 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
888886
t.vout[0].scriptPubKey = CScript() << OP_RETURN;
889887
CheckIsStandard(t);
890888

891-
// Only one TxoutType::NULL_DATA permitted in all cases
889+
// Multiple TxoutType::NULL_DATA are permitted
892890
t.vout.resize(2);
893891
t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
894892
t.vout[0].nValue = 0;
895893
t.vout[1].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
896894
t.vout[1].nValue = 0;
897-
CheckIsNotStandard(t, "multi-op-return");
895+
CheckIsStandard(t);
898896

899897
t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
900898
t.vout[1].scriptPubKey = CScript() << OP_RETURN;
901-
CheckIsNotStandard(t, "multi-op-return");
899+
CheckIsStandard(t);
902900

903901
t.vout[0].scriptPubKey = CScript() << OP_RETURN;
904902
t.vout[1].scriptPubKey = CScript() << OP_RETURN;
905-
CheckIsNotStandard(t, "multi-op-return");
903+
CheckIsStandard(t);
904+
905+
t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
906+
t.vout[1].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
907+
const auto datacarrier_size = t.vout[0].scriptPubKey.size() + t.vout[1].scriptPubKey.size();
908+
CheckIsStandard(t); // Default max relay should never trigger
909+
CheckIsStandard(t, /*max_op_return_relay=*/datacarrier_size);
910+
CheckIsNotStandard(t, "datacarrier", /*max_op_return_relay=*/datacarrier_size-1);
906911

907912
// Check large scriptSig (non-standard if size is >1650 bytes)
908913
t.vout.resize(1);

test/functional/feature_blocksxor.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ def set_test_params(self):
2323
self.extra_args = [[
2424
'-blocksxor=1',
2525
'-fastprune=1', # use smaller block files
26-
'-datacarriersize=100000', # needed to pad transaction with MiniWallet
2726
]]
2827

2928
def run_test(self):

test/functional/feature_maxuploadtarget.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ def set_test_params(self):
5151
self.num_nodes = 1
5252
self.extra_args = [[
5353
f"-maxuploadtarget={UPLOAD_TARGET_MB}M",
54-
"-datacarriersize=100000",
5554
]]
5655
self.supports_cli = False
5756

0 commit comments

Comments
 (0)