0
0
mirror of https://github.com/namecoin/namecoin-core synced 2025-10-06 00:22:46 +02:00
Files
namecoin-core/test/functional/name_segwit.py
Daniel Kraft 095937e761 Merge branch 'auxpow'
Use Txid in more places in the Namecoin code, most importantly for
queued transactions.
2025-08-18 20:12:05 +02:00

184 lines
6.1 KiB
Python
Executable File

#!/usr/bin/env python3
# Copyright (c) 2014-2021 Daniel Kraft
# Distributed under the MIT/X11 software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# RPC test for names at segwit addresses.
from test_framework.names import NameTestFramework
from test_framework.blocktools import (
add_witness_commitment,
create_block,
create_coinbase,
)
from test_framework.messages import (
CScriptWitness,
CTransaction,
CTxInWitness,
CTxWitness,
)
from test_framework.util import (
assert_equal,
assert_greater_than,
assert_raises_rpc_error,
softfork_active,
)
from decimal import Decimal
import io
SEGWIT_ACTIVATION_HEIGHT = 300
class NameSegwitTest (NameTestFramework):
def set_test_params (self):
self.setup_name_test ([[
"-debug",
"-par=1",
f"-testactivationheight=segwit@{SEGWIT_ACTIVATION_HEIGHT}"
]] * 1)
def checkNameValueAddr (self, name, value, addr):
"""
Verifies that the given name has the given value and address.
"""
data = self.checkName (0, name, value, None, False)
assert_equal (data['address'], addr)
def findUnspent (self, amount):
"""
Finds and returns an unspent input the node has with at least the
given value.
"""
unspents = self.node.listunspent ()
for u in unspents:
if u['amount'] >= amount:
return u
raise AssertionError ("Could not find suitable unspent output")
def buildDummySegwitNameUpdate (self, name, value, addr):
"""
Builds a transaction that updates the given name to the given value and
address. We assume that the name is at a native segwit script. The witness
of the transaction will be set to two dummy stack elements so that the
program itself is "well-formed" even if it won't execute successfully.
"""
data = self.node.name_show (name)
u = self.findUnspent (Decimal ('0.01'))
ins = [data, u]
outs = {addr: Decimal ('0.01')}
txHex = self.node.createrawtransaction (ins, outs)
nameOp = {"op": "name_update", "name": name, "value": value}
txHex = self.node.namerawtransaction (txHex, 0, nameOp)['hex']
txHex = self.node.signrawtransactionwithwallet (txHex)['hex']
tx = CTransaction ()
tx.deserialize (io.BytesIO (bytes.fromhex (txHex)))
tx.wit = CTxWitness ()
tx.wit.vtxinwit.append (CTxInWitness ())
tx.wit.vtxinwit[0].scriptWitness = CScriptWitness ()
tx.wit.vtxinwit[0].scriptWitness.stack = [b"dummy"] * 2
txHex = tx.serialize ().hex ()
return txHex
def tryUpdateSegwitName (self, name, value, addr):
"""
Tries to update the given name to the given value and address.
"""
txHex = self.buildDummySegwitNameUpdate (name, value, addr)
self.node.sendrawtransaction (txHex, 0)
def tryUpdateInBlock (self, name, value, addr, withWitness):
"""
Tries to update the given name with a dummy witness directly in a block
(to bypass any checks done on the mempool).
"""
txHex = self.buildDummySegwitNameUpdate (name, value, addr)
tx = CTransaction ()
tx.deserialize (io.BytesIO (bytes.fromhex (txHex)))
tip = self.node.getbestblockhash ()
height = self.node.getblockcount () + 1
nTime = self.node.getblockheader (tip)["mediantime"] + 1
block = create_block (int (tip, 16), create_coinbase (height), nTime,
version=4)
block.vtx.append (tx)
add_witness_commitment (block, 0)
block.solve ()
blkHex = block.serialize (withWitness).hex ()
return self.node.submitblock (blkHex)
def run_test (self):
self.node = self.nodes[0]
# Register a test name to a bech32 pure-segwit address.
addr = self.node.getnewaddress ("test", "bech32")
name = "d/test"
value = "{}"
new = self.node.name_new (name)
self.generate (self.node, 10)
self.firstupdateName (0, name, new, value, {"destAddress": addr})
self.generate (self.node, 5)
self.checkNameValueAddr (name, value, addr)
# Before segwit activation, the script should behave as anyone-can-spend.
# It will still fail due to non-mandatory flag checks when submitted
# into the mempool.
assert not softfork_active (self.node, "segwit")
assert_raises_rpc_error (-26, 'Script failed an OP_EQUALVERIFY operation',
self.tryUpdateSegwitName,
name, "wrong value", addr)
self.generate (self.node, 1)
self.checkNameValueAddr (name, value, addr)
# But directly in a block, the update should work with a dummy witness.
assert_equal (self.tryUpdateInBlock (name, "stolen", addr,
withWitness=False),
None)
self.checkNameValueAddr (name, "stolen", addr)
# Activate segwit. Since this makes the original name expire, we have
# to re-register it.
self.generate (self.node, 100)
new = self.node.name_new (name)
self.generate (self.node, 10)
self.firstupdateName (0, name, new, value, {"destAddress": addr})
self.generate (self.node, 5)
self.checkNameValueAddr (name, value, addr)
# Verify that now trying to update the name without a proper signature
# fails differently.
assert softfork_active (self.node, "segwit")
assert_equal (self.tryUpdateInBlock (name, "wrong value", addr,
withWitness=True),
'mempool-script-verify-flag-failed'
+ ' (Script failed an OP_EQUALVERIFY operation)')
self.checkNameValueAddr (name, value, addr)
# Updating the name ordinarily (with signature) should work fine even
# though it is at a segwit address. Also spending from P2SH-segwit
# should work fine.
addrP2SH = self.node.getnewaddress ("test", "p2sh-segwit")
self.node.name_update (name, "value 2", {"destAddress": addrP2SH})
self.generate (self.node, 1)
self.checkNameValueAddr (name, "value 2", addrP2SH)
self.node.name_update (name, "value 3", {"destAddress": addr})
self.generate (self.node, 1)
self.checkNameValueAddr (name, "value 3", addr)
if __name__ == '__main__':
NameSegwitTest (__file__).main ()