Run randomized tests with a number of "spenders". Steps: 1) Generate an appropriate UTXO for each spender to test spend conditions 2) Generate 100 random addresses of all wallet types: pkh/sh_wpkh/wpkh 3) Select random number of inputs from (1)
(self, node, spenders, input_counts)
| 1439 | self.lastblocktime = block['time'] |
| 1440 | |
| 1441 | def test_spenders(self, node, spenders, input_counts): |
| 1442 | """Run randomized tests with a number of "spenders". |
| 1443 | |
| 1444 | Steps: |
| 1445 | 1) Generate an appropriate UTXO for each spender to test spend conditions |
| 1446 | 2) Generate 100 random addresses of all wallet types: pkh/sh_wpkh/wpkh |
| 1447 | 3) Select random number of inputs from (1) |
| 1448 | 4) Select random number of addresses from (2) as outputs |
| 1449 | |
| 1450 | Each spender embodies a test; in a large randomized test, it is verified |
| 1451 | that toggling the valid argument to each lambda toggles the validity of |
| 1452 | the transaction. This is accomplished by constructing transactions consisting |
| 1453 | of all valid inputs, except one invalid one. |
| 1454 | """ |
| 1455 | |
| 1456 | # Construct a bunch of sPKs that send coins back to the host wallet |
| 1457 | self.log.info("- Constructing addresses for returning coins") |
| 1458 | host_spks = [] |
| 1459 | host_pubkeys = [] |
| 1460 | for i in range(16): |
| 1461 | addr = node.getnewaddress(address_type=random.choice(["legacy", "p2sh-segwit", "bech32"])) |
| 1462 | info = node.getaddressinfo(addr) |
| 1463 | spk = bytes.fromhex(info['scriptPubKey']) |
| 1464 | host_spks.append(spk) |
| 1465 | host_pubkeys.append(bytes.fromhex(info['pubkey'])) |
| 1466 | |
| 1467 | self.init_blockinfo(node) |
| 1468 | |
| 1469 | # Create transactions spending up to 50 of the wallet's inputs, with one output for each spender, and |
| 1470 | # one change output at the end. The transaction is constructed on the Python side to enable |
| 1471 | # having multiple outputs to the same address and outputs with no assigned address. The wallet |
| 1472 | # is then asked to sign it through signrawtransactionwithwallet, and then added to a block on the |
| 1473 | # Python side (to bypass standardness rules). |
| 1474 | self.log.info("- Creating test UTXOs...") |
| 1475 | random.shuffle(spenders) |
| 1476 | normal_utxos = [] |
| 1477 | mismatching_utxos = [] # UTXOs with input that requires mismatching output position |
| 1478 | done = 0 |
| 1479 | while done < len(spenders): |
| 1480 | # Compute how many UTXOs to create with this transaction |
| 1481 | count_this_tx = min(len(spenders) - done, (len(spenders) + 4) // 5, 10000) |
| 1482 | |
| 1483 | fund_tx = CTransaction() |
| 1484 | # Add the 50 highest-value inputs |
| 1485 | unspents = node.listunspent() |
| 1486 | random.shuffle(unspents) |
| 1487 | unspents.sort(key=lambda x: int(x["amount"] * 100000000), reverse=True) |
| 1488 | if len(unspents) > 50: |
| 1489 | unspents = unspents[:50] |
| 1490 | random.shuffle(unspents) |
| 1491 | balance = 0 |
| 1492 | for unspent in unspents: |
| 1493 | balance += int(unspent["amount"] * 100000000) |
| 1494 | txid = int(unspent["txid"], 16) |
| 1495 | fund_tx.vin.append(CTxIn(COutPoint(txid, int(unspent["vout"])), CScript())) |
| 1496 | # Add outputs |
| 1497 | cur_progress = done / len(spenders) |
| 1498 | next_progress = (done + count_this_tx) / len(spenders) |
no test coverage detected