diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 570a41ec35..3245200336 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -154,6 +154,7 @@ public: consensus.connect_genesis_outputs = false; anyonecanspend_aremine = false; enforce_pak = false; + multi_data_permitted = false; /** * The message start string is designed to be unlikely to occur in normal data. @@ -273,6 +274,7 @@ public: consensus.connect_genesis_outputs = false; anyonecanspend_aremine = false; enforce_pak = false; + multi_data_permitted = false; pchMessageStart[0] = 0x0b; pchMessageStart[1] = 0x11; @@ -367,6 +369,7 @@ public: consensus.connect_genesis_outputs = false; anyonecanspend_aremine = false; enforce_pak = false; + multi_data_permitted = false; pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0xbf; @@ -547,6 +550,9 @@ class CCustomParams : public CRegTestParams { enforce_pak = args.GetBoolArg("-enforce_pak", false); + // Allow multiple op_return outputs by relay policy + multi_data_permitted = args.GetBoolArg("-multi_data_permitted", true); + // bitcoin regtest is the parent chain by default parentGenesisBlockHash = uint256S(args.GetArg("-parentgenesisblockhash", "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); // Either it has a parent chain or not diff --git a/src/chainparams.h b/src/chainparams.h index 69e2fe1743..8a9e760f8b 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -88,6 +88,7 @@ public: bool anyonecanspend_aremine; const std::string& ParentBech32HRP() const { return parent_bech32_hrp; } bool GetEnforcePak() const { return enforce_pak; } + bool GetMultiDataPermitted() const { return multi_data_permitted; } protected: CChainParams() {} @@ -113,6 +114,7 @@ protected: uint256 parentGenesisBlockHash; std::string parent_bech32_hrp; bool enforce_pak; + bool multi_data_permitted; }; /** diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index e038d41dff..90a3a6de9e 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -39,6 +39,7 @@ void SetupChainParamsBaseOptions() gArgs.AddArg("-fedpegscript", "The script for the federated peg.", false, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-enforce_pak", "Causes standardness checks to enforce Pegout Authorization Key(PAK) validation, and miner to include PAK commitments when configured. Can not be set when acceptnonstdtx is set to true.", false, OptionsCategory::ELEMENTS); + gArgs.AddArg("-multi_data_permitted", "Allow relay of multiple OP_RETURN outputs. (default: true)", false, OptionsCategory::ELEMENTS); } static std::unique_ptr globalChainBaseParams; diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 270e0d48aa..55a2860f4d 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -149,7 +149,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason) } // only one OP_RETURN txout is permitted - if (nDataOut > 1) { + if (!params.GetMultiDataPermitted() && nDataOut > 1) { reason = "multi-op-return"; return false; } diff --git a/test/bitcoin_functional/functional/test_framework/util.py b/test/bitcoin_functional/functional/test_framework/util.py index a90d19a3b1..a27a407c88 100644 --- a/test/bitcoin_functional/functional/test_framework/util.py +++ b/test/bitcoin_functional/functional/test_framework/util.py @@ -311,6 +311,7 @@ def initialize_datadir(dirname, n, chain): f.write("anyonecanspendaremine=0\n") f.write("con_blockheightinheader=0\n") f.write("con_signed_blocks=0\n") + f.write("multi_data_permitted=0\n") f.write("walletrbf=0\n") # Default is 1 in Elements f.write("con_bip34height=100000000\n") f.write("con_bip65height=1351\n") diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index 44426a0ff7..49058b430c 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -260,11 +260,12 @@ class MempoolAcceptanceTest(BitcoinTestFramework): result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: dust'}], rawtxs=[bytes_to_hex_str(tx.serialize())], ) + # Elements: We allow multi op_return outputs by default. This still fails because relay fee isn't met tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff']) tx.vout = [tx.vout[0]] * 2 self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: multi-op-return'}], + result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '66: min relay fee not met'}], rawtxs=[bytes_to_hex_str(tx.serialize())], )