From 57c8bc8453a5bf41f325e64628c6dad8c9147392 Mon Sep 17 00:00:00 2001 From: Torkel Rogstad Date: Wed, 9 Oct 2024 16:46:09 +0200 Subject: [PATCH] contrib: add OP_RETURN message capability to signet miner --- contrib/signet/miner | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/contrib/signet/miner b/contrib/signet/miner index 585399785b0486..3f3e9f13e6ad63 100755 --- a/contrib/signet/miner +++ b/contrib/signet/miner @@ -21,7 +21,7 @@ sys.path.insert(0, PATH_BASE_TEST_FUNCTIONAL) from test_framework.blocktools import get_witness_script, script_BIP34_coinbase_height # noqa: E402 from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, from_binary, from_hex, ser_string, ser_uint256, tx_from_hex # noqa: E402 from test_framework.psbt import PSBT, PSBTMap, PSBT_GLOBAL_UNSIGNED_TX, PSBT_IN_FINAL_SCRIPTSIG, PSBT_IN_FINAL_SCRIPTWITNESS, PSBT_IN_NON_WITNESS_UTXO, PSBT_IN_SIGHASH_TYPE # noqa: E402 -from test_framework.script import CScript, CScriptOp # noqa: E402 +from test_framework.script import CScript, CScriptOp, OP_RETURN # noqa: E402 logging.basicConfig( format='%(asctime)s %(levelname)s %(message)s', @@ -93,7 +93,7 @@ def finish_block(block, signet_solution, grind_cmd): block.rehash() return block -def generate_psbt(tmpl, reward_spk, *, blocktime=None, poolid=None): +def generate_psbt(tmpl, reward_spk, *, blocktime=None, poolid=None, extra_vouts=[]): signet_spk = tmpl["signet_challenge"] signet_spk_bin = bytes.fromhex(signet_spk) @@ -103,7 +103,7 @@ def generate_psbt(tmpl, reward_spk, *, blocktime=None, poolid=None): cbtx = CTransaction() cbtx.vin = [CTxIn(COutPoint(0, 0xffffffff), scriptSig, 0xffffffff)] - cbtx.vout = [CTxOut(tmpl["coinbasevalue"], reward_spk)] + cbtx.vout = [CTxOut(tmpl["coinbasevalue"], reward_spk)].append(extra_vouts) cbtx.vin[0].nSequence = 2**32-2 cbtx.rehash() @@ -136,6 +136,22 @@ def generate_psbt(tmpl, reward_spk, *, blocktime=None, poolid=None): psbt.o = [ PSBTMap() ] return psbt.to_base64() +def get_op_return_vouts(args): + vouts = [] + + for message in args.op_return_vout: + if message is None: + continue + + try: + decoded_message = bytes.fromhex(message) + except ValueError: + raise Exception("message must be hex-encoded bytes") + + vouts.append(CTxOut(0, CScript([OP_RETURN, decoded_message]))) + + return vouts + def get_poolid(args): if args.poolid is not None: return args.poolid.encode('utf8') @@ -172,10 +188,11 @@ def get_reward_addr_spk(args, height): return reward_addr, reward_spk def do_genpsbt(args): + op_return_vouts = get_op_return_vouts(args) poolid = get_poolid(args) tmpl = json.load(sys.stdin) _, reward_spk = get_reward_addr_spk(args, tmpl["height"]) - psbt = generate_psbt(tmpl, reward_spk, poolid=poolid) + psbt = generate_psbt(tmpl, reward_spk, poolid=poolid, extra_vouts=op_return_vouts) print(psbt) def do_solvepsbt(args): @@ -229,7 +246,7 @@ class Generate: standby_delay=0, backup_delay=0, set_block_time=None, # 10 minutes, adjusted for the off-by-one bug block_interval=600.0*2016/2015, - poolid=None): + poolid=None, extra_vouts=[]): if multiminer is None: multiminer = (0, 1, 1) (self.multi_low, self.multi_high, self.multi_period) = multiminer @@ -241,6 +258,8 @@ class Generate: self.set_block_time = set_block_time self.poolid = poolid self.block_interval = block_interval + self.extra_vouts = extra_vouts + def next_block_delta(self, last_nbits, last_hash): # strategy: @@ -324,7 +343,10 @@ class Generate: return tmpl def mine(self, bcli, grind_cmd, tmpl, reward_spk): - psbt = generate_psbt(tmpl, reward_spk, blocktime=self.mine_time, poolid=self.poolid) + psbt = generate_psbt( + tmpl, reward_spk, blocktime=self.mine_time, + poolid=self.poolid, extra_vouts=self.extra_vouts, + ) input_stream = os.linesep.join([psbt, "true", "ALL"]).encode('utf8') psbt_signed = json.loads(bcli("-stdin", "walletprocesspsbt", input=input_stream)) if not psbt_signed.get("complete",False): @@ -392,7 +414,8 @@ def do_generate(args): gen = Generate(multiminer=my_blocks, ultimate_target=ultimate_target, poisson=args.poisson, max_interval=args.max_interval, standby_delay=args.standby_delay, backup_delay=args.backup_delay, set_block_time=args.set_block_time, poolid=poolid, - block_interval=args.block_interval) + block_interval=args.block_interval, + extra_vouts=get_op_return_vouts(args)) mined_blocks = 0 bestheader = {"hash": None} @@ -550,6 +573,7 @@ def main(): pool = sp.add_mutually_exclusive_group() pool.add_argument("--poolnum", default=None, type=int, help="Identify blocks that you mine") pool.add_argument("--poolid", default=None, type=str, help="Identify blocks that you mine (eg: /signet:1/)") + pool.add_argument("--op-return-vout", default=None, action="append", type=str, help="Extra OP_RETURN vout to add to the coinbase") for sp in [solvepsbt, generate, calibrate]: sp.add_argument("--grind-cmd", default=None, type=str, required=(sp==calibrate), help="Command to grind a block header for proof-of-work")