Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc-wallet-standardness.py
Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
std_node, nonstd_node = self.nodes | std_node, nonstd_node = self.nodes | ||||
address_nonstd = nonstd_node.getnewaddress() | address_nonstd = nonstd_node.getnewaddress() | ||||
# make and mature some coins for the nonstandard node | # make and mature some coins for the nonstandard node | ||||
nonstd_node.generate(120) | nonstd_node.generate(120) | ||||
sync_blocks(self.nodes) | sync_blocks(self.nodes) | ||||
def fund_and_test_wallet(scriptPubKey, shouldBeStandard, shouldBeInWallet, amount=10000, spendfee=500, nonstd_error="scriptpubkey (code 64)"): | def fund_and_test_wallet(scriptPubKey, shouldBeStandard, shouldBeInWallet, | ||||
amount=10000, spendfee=500, nonstd_error="scriptpubkey (code 64)", canSign=None): | |||||
""" Get the nonstandard node to fund a transaction, test its | """ Get the nonstandard node to fund a transaction, test its | ||||
standardness by trying to broadcast on the standard node, then | standardness by trying to broadcast on the standard node, then | ||||
mine it and see if it ended up in the standard node's wallet. | mine it and see if it ended up in the standard node's wallet. | ||||
Finally, it attempts to spend the coin. | Finally, it attempts to spend the coin. | ||||
""" | """ | ||||
if canSign is None: | |||||
canSign = shouldBeInWallet | |||||
self.log.info("Trying script {}".format(scriptPubKey.hex(),)) | self.log.info("Trying script {}".format(scriptPubKey.hex(),)) | ||||
# get nonstandard node to fund the script | # get nonstandard node to fund the script | ||||
tx = CTransaction() | tx = CTransaction() | ||||
tx.vout.append(CTxOut(max(amount, 10000), scriptPubKey)) | tx.vout.append(CTxOut(max(amount, 10000), scriptPubKey)) | ||||
rawtx = nonstd_node.fundrawtransaction( | rawtx = nonstd_node.fundrawtransaction( | ||||
ToHex(tx), {'lockUnspents': True, 'changePosition': 1})['hex'] | ToHex(tx), {'lockUnspents': True, 'changePosition': 1})['hex'] | ||||
# fundrawtransaction doesn't like to fund dust outputs, so we | # fundrawtransaction doesn't like to fund dust outputs, so we | ||||
Show All 27 Lines | def run_test(self): | ||||
sync_blocks(self.nodes) | sync_blocks(self.nodes) | ||||
wallet_outpoints = {(entry['txid'], entry['vout']) | wallet_outpoints = {(entry['txid'], entry['vout']) | ||||
for entry in std_node.listunspent()} | for entry in std_node.listunspent()} | ||||
# calculate wallet balance change just as a double check | # calculate wallet balance change just as a double check | ||||
balance_change = std_node.getbalance() - balance_initial | balance_change = std_node.getbalance() - balance_initial | ||||
if shouldBeInWallet: | |||||
assert (txid, 0) in wallet_outpoints | |||||
assert balance_change == amount * SATOSHI | |||||
else: | |||||
assert (txid, 0) not in wallet_outpoints | |||||
assert balance_change == 0 | |||||
# try spending the funds using the wallet. | # try spending the funds using the wallet. | ||||
outamount = (amount - spendfee) * SATOSHI | outamount = (amount - spendfee) * SATOSHI | ||||
if outamount < 546 * SATOSHI: | if outamount < 546 * SATOSHI: | ||||
# If the final amount would be too small, then just donate | # If the final amount would be too small, then just donate | ||||
# to miner fees. | # to miner fees. | ||||
outputs = [{"data": b"to miner, with love".hex()}] | outputs = [{"data": b"to miner, with love".hex()}] | ||||
else: | else: | ||||
outputs = [{address_nonstd: outamount}] | outputs = [{address_nonstd: outamount}] | ||||
spendtx = std_node.createrawtransaction( | spendtx = std_node.createrawtransaction( | ||||
[{'txid': txid, 'vout': 0}], outputs) | [{'txid': txid, 'vout': 0}], outputs) | ||||
signresult = std_node.signrawtransactionwithwallet(spendtx) | signresult = std_node.signrawtransactionwithwallet(spendtx) | ||||
if shouldBeInWallet: | if canSign: | ||||
assert (txid, 0) in wallet_outpoints | |||||
assert balance_change == amount * SATOSHI | |||||
assert_equal(signresult['complete'], True) | assert_equal(signresult['complete'], True) | ||||
txid = std_node.sendrawtransaction(signresult['hex']) | txid = std_node.sendrawtransaction(signresult['hex']) | ||||
[blockhash] = std_node.generate(1) | [blockhash] = std_node.generate(1) | ||||
# make sure it was mined | # make sure it was mined | ||||
assert txid in std_node.getblock(blockhash)["tx"] | assert txid in std_node.getblock(blockhash)["tx"] | ||||
sync_blocks(self.nodes) | sync_blocks(self.nodes) | ||||
else: | else: | ||||
assert (txid, 0) not in wallet_outpoints | |||||
assert balance_change == 0 | |||||
# signresult['errors'] will vary depending on input script. What | # signresult['errors'] will vary depending on input script. What | ||||
# occurs is that in sign.cpp, ProduceSignature gets back | # occurs is that in sign.cpp, ProduceSignature gets back | ||||
# solved=false since SignStep sees a nonstandard input. Then, | # solved=false since SignStep sees a nonstandard input. Then, | ||||
# an empty SignatureData results. Back in rawtransaction.cpp's | # an empty SignatureData results. Back in rawtransaction.cpp's | ||||
# SignTransaction, it will then attempt to execute the | # SignTransaction, it will then attempt to execute the | ||||
# scriptPubKey with an empty scriptSig. A P2PKH script will thus | # scriptPubKey with an empty scriptSig. A P2PKH script will thus | ||||
# fail at OP_DUP with stack error, and P2PK/Multisig will fail | # fail at OP_DUP with stack error, and P2PK/Multisig will fail | ||||
# once they hit a nonminimal push. The error message is just an | # once they hit a nonminimal push. The error message is just an | ||||
Show All 15 Lines | def run_test(self): | ||||
# P2PKH | # P2PKH | ||||
fund_and_test_wallet(CScript( | fund_and_test_wallet(CScript( | ||||
[OP_DUP, OP_HASH160, pubkeyhash, OP_EQUALVERIFY, OP_CHECKSIG]), True, True) | [OP_DUP, OP_HASH160, pubkeyhash, OP_EQUALVERIFY, OP_CHECKSIG]), True, True) | ||||
fund_and_test_wallet(CScript( | fund_and_test_wallet(CScript( | ||||
[OP_DUP, OP_HASH160, OP_PUSHDATA1, pubkeyhash, OP_EQUALVERIFY, OP_CHECKSIG]), False, False) | [OP_DUP, OP_HASH160, OP_PUSHDATA1, pubkeyhash, OP_EQUALVERIFY, OP_CHECKSIG]), False, False) | ||||
# Bare multisig | # Bare multisig | ||||
fund_and_test_wallet( | fund_and_test_wallet( | ||||
CScript([OP_1, pubkey, OP_1, OP_CHECKMULTISIG]), True, True) | CScript([OP_1, pubkey, OP_1, OP_CHECKMULTISIG]), True, False, canSign=True) | ||||
fund_and_test_wallet( | fund_and_test_wallet( | ||||
CScript([OP_1, OP_PUSHDATA1, pubkey, OP_1, OP_CHECKMULTISIG]), False, False) | CScript([OP_1, OP_PUSHDATA1, pubkey, OP_1, OP_CHECKMULTISIG]), False, False) | ||||
fund_and_test_wallet( | fund_and_test_wallet( | ||||
CScript([OP_1, pubkey, b'\x01', OP_CHECKMULTISIG]), False, False) | CScript([OP_1, pubkey, b'\x01', OP_CHECKMULTISIG]), False, False) | ||||
fund_and_test_wallet( | fund_and_test_wallet( | ||||
CScript([b'\x01', pubkey, OP_1, OP_CHECKMULTISIG]), False, False) | CScript([b'\x01', pubkey, OP_1, OP_CHECKMULTISIG]), False, False) | ||||
# Note: 1-of-5 is nonstandard to fund but standard to spend. | # Note: 1-of-5 is nonstandard to fund but standard to spend. | ||||
fund_and_test_wallet( | fund_and_test_wallet( | ||||
CScript([OP_1, pubkey, pubkey, pubkey, pubkey, pubkey, OP_5, OP_CHECKMULTISIG]), False, True) | CScript([OP_1, pubkey, pubkey, pubkey, pubkey, pubkey, OP_5, OP_CHECKMULTISIG]), False, False, canSign=True) | ||||
fund_and_test_wallet( | fund_and_test_wallet( | ||||
CScript([OP_1, pubkey, pubkey, pubkey, OP_PUSHDATA1, pubkey, pubkey, OP_5, OP_CHECKMULTISIG]), False, False) | CScript([OP_1, pubkey, pubkey, pubkey, OP_PUSHDATA1, pubkey, pubkey, OP_5, OP_CHECKMULTISIG]), False, False) | ||||
# Dust also is nonstandard to fund but standard to spend. | # Dust also is nonstandard to fund but standard to spend. | ||||
fund_and_test_wallet( | fund_and_test_wallet( | ||||
CScript([pubkey, OP_CHECKSIG]), False, True, amount=200, nonstd_error="dust (code 64)") | CScript([pubkey, OP_CHECKSIG]), False, True, amount=200, nonstd_error="dust (code 64)") | ||||
# and we end with an empty wallet | # and we end with an empty wallet | ||||
assert_equal(std_node.getbalance(), 0) | assert_equal(std_node.getbalance(), 0) | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
WalletStandardnessTest().main() | WalletStandardnessTest().main() |