def run_test(self): self.nodes[0].generate(110) # Obtain some transparent funds midAddr = self.nodes[0].getnewshieldaddress() # Shield almost all the balance self.nodes[0].shieldsendmany(get_coinstake_address(self.nodes[0]), [{ "address": midAddr, "amount": Decimal(2400) }]) self.sync_all() self.nodes[1].generate(1) self.sync_all() taddrSource = self.nodes[0].getnewaddress() for _ in range(6): recipients = [{"address": taddrSource, "amount": Decimal('3')}] self.nodes[0].shieldsendmany(midAddr, recipients, 1) self.sync_all() self.nodes[1].generate(1) self.sync_all() def check_change_taddr_reuse(target, isTargetShielded): recipients = [{"address": target, "amount": Decimal('1')}] # Send funds to recipient address twice txid1 = self.nodes[0].shieldsendmany(taddrSource, recipients, 1) self.nodes[1].generate(1) self.sync_all() txid2 = self.nodes[0].shieldsendmany(taddrSource, recipients, 1) self.nodes[1].generate(1) self.sync_all() # Verify that the two transactions used different change addresses tx1 = self.nodes[0].getrawtransaction(txid1, 1) tx2 = self.nodes[0].getrawtransaction(txid2, 1) assert_true(len(tx1['vout']) >= 1) # at least one output assert_true(len(tx2['vout']) >= 1) for i in range(len(tx1['vout'])): tx1OutAddrs = tx1['vout'][i]['scriptPubKey']['addresses'] tx2OutAddrs = tx2['vout'][i]['scriptPubKey']['addresses'] if tx1OutAddrs != [target]: print('Source address: %s' % taddrSource) print('TX1 change address: %s' % tx1OutAddrs[0]) print('TX2 change address: %s' % tx2OutAddrs[0]) assert (tx1OutAddrs != tx2OutAddrs) taddr = self.nodes[0].getnewaddress() saplingAddr = self.nodes[0].getnewshieldaddress() print() print('Checking shieldsendmany(taddr->Sapling)') check_change_taddr_reuse(saplingAddr, True) print() print('Checking shieldsendmany(taddr->taddr)') check_change_taddr_reuse(taddr, False)
def run_test(self): node = self.nodes[0] node.generate(110) # Obtain some transparent funds midAddr = node.getnewshieldaddress() # Shield almost all the balance node.shieldsendmany(get_coinstake_address(node), [{ "address": midAddr, "amount": Decimal(2400) }]) node.generate(1) taddrSource = node.getnewaddress() for _ in range(6): recipients = [{"address": taddrSource, "amount": Decimal('3')}] node.shieldsendmany(midAddr, recipients, 1) node.generate(1) def check_change_taddr_reuse(target): recipients = [{"address": target, "amount": Decimal('1')}] # Send funds to recipient address twice txid1 = node.shieldsendmany(taddrSource, recipients, 1) node.generate(1) txid2 = node.shieldsendmany(taddrSource, recipients, 1) node.generate(1) # Verify that the two transactions used different change addresses tx1 = node.getrawtransaction(txid1, 1) tx2 = node.getrawtransaction(txid2, 1) assert_greater_than_or_equal(len(tx1['vout']), 1) # at least one output assert_greater_than_or_equal(len(tx2['vout']), 1) for i in range(len(tx1['vout'])): tx1OutAddrs = tx1['vout'][i]['scriptPubKey']['addresses'][0] tx2OutAddrs = tx2['vout'][i]['scriptPubKey']['addresses'][0] if tx1OutAddrs != target: self.log.info('Source address: %s' % taddrSource) self.log.info('TX1 change address: %s' % tx1OutAddrs) self.log.info('TX2 change address: %s' % tx2OutAddrs) assert tx1OutAddrs != tx2OutAddrs taddr = node.getnewaddress() saplingAddr = node.getnewshieldaddress() self.log.info('Checking shieldsendmany(taddr->Sapling)') check_change_taddr_reuse(saplingAddr) self.log.info('Checking shieldsendmany(taddr->taddr)') check_change_taddr_reuse(taddr)
def run_test(self): self.nodes[0].generate(2) self.sync_all() assert_equal(self.nodes[1].getblockcount(), 202) taddr1 = self.nodes[1].getnewaddress() saplingAddr0 = self.nodes[0].getnewshieldedaddress() saplingAddr1 = self.nodes[1].getnewshieldedaddress() # Verify addresses assert (saplingAddr0 in self.nodes[0].listshieldedaddresses()) assert (saplingAddr1 in self.nodes[1].listshieldedaddresses()) # Verify balance assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('0')) assert_equal(self.nodes[1].getshieldedbalance(saplingAddr1), Decimal('0')) assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('0')) recipients = [{"address": saplingAddr0, "amount": Decimal('10')}] # Try fee too low fee_too_low = 0.001 self.log.info("Trying to send a transaction with fee too low...") assert_raises_rpc_error( -4, "Fee set (%.3f) too low. Must be at least" % fee_too_low, self.nodes[0].rawshieldedsendmany, "from_transparent", recipients, 1, fee_too_low) # Try fee too high. fee_too_high = 20 self.log.info( "Good. It was not possible. Now try a tx with fee too high...") assert_raises_rpc_error( -4, "The transaction fee is too high: %.2f >" % fee_too_high, self.nodes[0].rawshieldedsendmany, "from_transparent", recipients, 1, fee_too_high) # Trying to send a rawtx with low fee directly self.log.info("Good. It was not possible. Now try with a raw tx...") self.restart_node(0, extra_args=self.extra_args[0] + ['-minrelaytxfee=0.0000001']) rawtx = self.nodes[0].rawshieldedsendmany("from_transparent", recipients, 1)["hex"] self.restart_node(0, extra_args=self.extra_args[0]) connect_nodes(self.nodes[0], 1) assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, rawtx) self.log.info("Good. Not accepted in the mempool.") # Fixed fee fee = 1 # Node 0 shields some funds # taddr -> Sapling self.log.info("TX 1: shield funds from specified transparent address.") mytxid1 = self.nodes[0].shieldedsendmany( get_coinstake_address(self.nodes[0]), recipients, 1, fee) # shield more funds automatically selecting the transparent inputs self.log.info("TX 2: shield funds from any transparent address.") mytxid2 = self.nodes[0].shieldedsendmany("from_transparent", recipients, 1, fee) # Verify priority of tx is INF_PRIORITY, defined as 1E+25 (10000000000000000000000000) self.check_tx_priority([mytxid1, mytxid2]) self.log.info("Priority for tx1 and tx2 checks out") self.nodes[2].generate(1) self.sync_all() # shield more funds creating and then sending a raw transaction self.log.info( "TX 3: shield funds creating and sending raw transaction.") tx_json = self.nodes[0].rawshieldedsendmany("from_transparent", recipients, 1, fee) # Check SPORK_20 for sapling maintenance mode SPORK_20 = "SPORK_20_SAPLING_MAINTENANCE" self.activate_spork(0, SPORK_20) self.wait_for_spork(True, SPORK_20) assert_raises_rpc_error(-26, "bad-tx-sapling-maintenance", self.nodes[0].sendrawtransaction, tx_json["hex"]) self.log.info("Good. Not accepted when SPORK_20 is active.") # Try with RPC... assert_raises_rpc_error(-8, "Invalid parameter, Sapling not active yet", self.nodes[0].shieldedsendmany, "from_transparent", recipients, 1, fee) # Disable SPORK_20 and retry sleep(5) self.deactivate_spork(0, SPORK_20) self.wait_for_spork(False, SPORK_20) mytxid3 = self.nodes[0].sendrawtransaction(tx_json["hex"]) self.log.info("Good. Accepted when SPORK_20 is not active.") # Verify priority of tx is INF_PRIORITY, defined as 1E+25 (10000000000000000000000000) self.check_tx_priority([mytxid3]) self.log.info("Priority for tx3 checks out") self.nodes[2].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('30')) assert_equal(self.nodes[1].getshieldedbalance(saplingAddr1), Decimal('0')) assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('0')) self.log.info("Balances check out") # Now disconnect the block, activate SPORK_20, and try to reconnect it disconnect_nodes(self.nodes[0], 1) tip_hash = self.nodes[0].getbestblockhash() self.nodes[0].invalidateblock(tip_hash) assert tip_hash != self.nodes[0].getbestblockhash() assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('20')) self.log.info( "Now trying to connect block with shielded tx, when SPORK_20 is active" ) self.activate_spork(0, SPORK_20) self.nodes[0].reconsiderblock(tip_hash) assert tip_hash != self.nodes[0].getbestblockhash( ) # Block NOT connected assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('20')) self.log.info("Good. Not possible.") # Deactivate SPORK_20 and reconnect sleep(1) self.deactivate_spork(0, SPORK_20) self.nodes[0].reconsiderblock(tip_hash) assert_equal(tip_hash, self.nodes[0].getbestblockhash()) # Block connected assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('30')) self.log.info( "Reconnected after deactivation of SPORK_20. Balance restored.") connect_nodes(self.nodes[0], 1) # Node 0 sends some shielded funds to node 1 # Sapling -> Sapling # -> Sapling (change) self.log.info( "TX 4: shielded transaction from specified sapling address.") recipients4 = [{"address": saplingAddr1, "amount": Decimal('10')}] mytxid4 = self.nodes[0].shieldedsendmany(saplingAddr0, recipients4, 1, fee) self.check_tx_priority([mytxid4]) self.nodes[2].generate(1) self.sync_all() # Send more shielded funds (this time with automatic selection of the source) self.log.info("TX 5: shielded transaction from any sapling address.") recipients5 = [{"address": saplingAddr1, "amount": Decimal('5')}] mytxid5 = self.nodes[0].shieldedsendmany("from_shielded", recipients5, 1, fee) self.check_tx_priority([mytxid5]) self.nodes[2].generate(1) self.sync_all() # Send more shielded funds (with create + send raw transaction) self.log.info("TX 6: shielded raw transaction.") tx_json = self.nodes[0].rawshieldedsendmany("from_shielded", recipients5, 1, fee) mytxid6 = self.nodes[0].sendrawtransaction(tx_json["hex"]) self.check_tx_priority([mytxid6]) self.nodes[2].generate(1) self.sync_all() # Shield more funds to a different address to verify multi-source notes spending saplingAddr2 = self.nodes[0].getnewshieldedaddress() self.log.info( "TX 7: shield funds to later verify multi source notes spending.") recipients = [{"address": saplingAddr2, "amount": Decimal('10')}] mytxid7 = self.nodes[0].shieldedsendmany( get_coinstake_address(self.nodes[0]), recipients, 1, fee) self.check_tx_priority([mytxid7]) self.nodes[2].generate(5) self.sync_all() # Verify multi-source notes spending tAddr0 = self.nodes[0].getnewaddress() self.log.info("TX 8: verifying multi source notes spending.") recipients = [{"address": tAddr0, "amount": Decimal('11')}] mytxid8 = self.nodes[0].shieldedsendmany("from_shielded", recipients, 1, fee) self.check_tx_priority([mytxid8]) self.nodes[2].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('3')) # 30 received - (20 sent + 3 fee) - 4 sent assert_equal(self.nodes[1].getshieldedbalance(saplingAddr1), Decimal('20')) # 20 received assert_equal(self.nodes[0].getshieldedbalance(saplingAddr2), Decimal('2')) # 10 received - 10 sent + 2 change assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('0')) assert_equal(self.nodes[0].getshieldedbalance(), Decimal('5')) self.log.info("Balances check out") # Node 1 sends some shielded funds to node 0, as well as unshielding # Sapling -> Sapling # -> taddr # -> Sapling (change) self.log.info("TX 10: deshield funds from specified sapling address.") recipients7 = [{"address": saplingAddr0, "amount": Decimal('8')}] recipients7.append({"address": taddr1, "amount": Decimal('10')}) mytxid7 = self.nodes[1].shieldedsendmany(saplingAddr1, recipients7, 1, fee) self.check_tx_priority([mytxid7]) self.nodes[2].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('11')) # 3 prev balance + 8 received assert_equal(self.nodes[1].getshieldedbalance(saplingAddr1), Decimal('1')) # 20 prev balance - (18 sent + 1 fee) assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('10')) self.log.info("Balances check out") # Verify existence of Sapling related JSON fields resp = self.nodes[0].getrawtransaction(mytxid7, 1) assert_equal(Decimal(resp['valueBalance']), Decimal( '11.00')) # 20 shielded input - 8 shielded spend - 1 change assert_equal(len(resp['vShieldedSpend']), 3) assert_equal(len(resp['vShieldedOutput']), 2) assert ('bindingSig' in resp) shieldedSpend = resp['vShieldedSpend'][0] assert ('cv' in shieldedSpend) assert ('anchor' in shieldedSpend) assert ('nullifier' in shieldedSpend) assert ('rk' in shieldedSpend) assert ('proof' in shieldedSpend) assert ('spendAuthSig' in shieldedSpend) shieldedOutput = resp['vShieldedOutput'][0] assert ('cv' in shieldedOutput) assert ('cmu' in shieldedOutput) assert ('ephemeralKey' in shieldedOutput) assert ('encCiphertext' in shieldedOutput) assert ('outCiphertext' in shieldedOutput) assert ('proof' in shieldedOutput) self.log.info("Raw transaction decoding checks out") # Verify importing a spending key will update the nullifiers and witnesses correctly self.log.info("Checking exporting/importing a spending key...") sk0 = self.nodes[0].exportsaplingkey(saplingAddr0) saplingAddrInfo0 = self.nodes[2].importsaplingkey(sk0, "yes") assert_equal(saplingAddrInfo0["address"], saplingAddr0) assert_equal( self.nodes[2].getshieldedbalance(saplingAddrInfo0["address"]), Decimal('11')) sk1 = self.nodes[1].exportsaplingkey(saplingAddr1) saplingAddrInfo1 = self.nodes[2].importsaplingkey(sk1, "yes") assert_equal(saplingAddrInfo1["address"], saplingAddr1) assert_equal( self.nodes[2].getshieldedbalance(saplingAddrInfo1["address"]), Decimal('1')) # Verify importing a viewing key will update the nullifiers and witnesses correctly self.log.info("Checking exporting/importing a viewing key...") extfvk0 = self.nodes[0].exportsaplingviewingkey(saplingAddr0) saplingAddrInfo0 = self.nodes[3].importsaplingviewingkey( extfvk0, "yes") assert_equal(saplingAddrInfo0["address"], saplingAddr0) assert_equal( Decimal(self.nodes[3].getshieldedbalance( saplingAddrInfo0["address"], 1, True)), Decimal('11')) extfvk1 = self.nodes[1].exportsaplingviewingkey(saplingAddr1) saplingAddrInfo1 = self.nodes[3].importsaplingviewingkey( extfvk1, "yes") assert_equal(saplingAddrInfo1["address"], saplingAddr1) assert_equal( self.nodes[3].getshieldedbalance(saplingAddrInfo1["address"], 1, True), Decimal('1')) # no balance in the wallet assert_equal(self.nodes[3].getshieldedbalance(), Decimal('0')) # watch only balance assert_equal(self.nodes[3].getshieldedbalance("*", 1, True), Decimal('12.00')) # Now shield some funds using sendmany self.log.info( "TX11: Shielding coins to multiple destinations with sendmany RPC..." ) prev_balance = self.nodes[0].getbalance() recipients8 = { saplingAddr0: Decimal('8'), saplingAddr1: Decimal('1'), saplingAddr2: Decimal('0.5') } mytxid11 = self.nodes[0].sendmany("", recipients8) self.check_tx_priority([mytxid11]) self.log.info("Done. Checking details and balances...") # Decrypted transaction details should be correct pt = self.nodes[0].viewshieldedtransaction(mytxid11) fee = pt["fee"] assert_equal(pt['txid'], mytxid11) assert_equal(len(pt['spends']), 0) assert_equal(len(pt['outputs']), 3) found = [False] * 3 for out in pt['outputs']: assert_equal(pt['outputs'].index(out), out['output']) if out['address'] == saplingAddr0: assert_equal(out['outgoing'], False) assert_equal(out['value'], Decimal('8')) found[0] = True elif out['address'] == saplingAddr1: assert_equal(out['outgoing'], True) assert_equal(out['value'], Decimal('1')) found[1] = True else: assert_equal(out['address'], saplingAddr2) assert_equal(out['outgoing'], False) assert_equal(out['value'], Decimal('0.5')) found[2] = True assert_equal(found, [True] * 3) # Verify balance self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('19')) # 11 prev balance + 8 received assert_equal(self.nodes[1].getshieldedbalance(saplingAddr1), Decimal('2')) # 1 prev balance + 1 received assert_equal(self.nodes[0].getshieldedbalance(saplingAddr2), Decimal('2.5')) # 2 prev balance + 0.5 received # Balance of node 0 is: prev_balance - 1 PIV (+fee) sent externally + 250 PIV matured coinbase assert_equal( self.nodes[0].getbalance(), satoshi_round(prev_balance + Decimal('249') - Decimal(fee))) # Now shield some funds using sendtoaddress self.log.info("TX12: Shielding coins with sendtoaddress RPC...") prev_balance = self.nodes[0].getbalance() mytxid12 = self.nodes[0].sendtoaddress(saplingAddr0, Decimal('10')) self.check_tx_priority([mytxid12]) self.log.info("Done. Checking details and balances...") # Decrypted transaction details should be correct pt = self.nodes[0].viewshieldedtransaction(mytxid12) fee = pt["fee"] assert_equal(pt['txid'], mytxid12) assert_equal(len(pt['spends']), 0) assert_equal(len(pt['outputs']), 1) out = pt['outputs'][0] assert_equal(out['address'], saplingAddr0) assert_equal(out['outgoing'], False) assert_equal(out['value'], Decimal('10')) # Verify balance self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('29')) # 19 prev balance + 10 received self.log.info("All good.")
def run_test (self): self.nodes[0].generate(1) # activate Sapling self.sync_all() # add shield addr to node 0 myzaddr0 = self.nodes[0].getnewshieldaddress() # send node 0 taddr to shield addr to get out of coinbase # Tests using the default cached chain have one address per coinbase output mytaddr = get_coinstake_address(self.nodes[0]) recipients = [] recipients.append({"address":myzaddr0, "amount":Decimal('10.0') - Decimal('1')}) # utxo amount less fee self.nodes[0].shieldsendmany(mytaddr, recipients) self.nodes[0].generate(1) self.sync_all() # add shield addr to node 2 myzaddr = self.nodes[2].getnewshieldaddress() # import node 2 shield addr into node 1 myzkey = self.nodes[2].exportsaplingkey(myzaddr) self.nodes[1].importsaplingkey(myzkey) # encrypt node 1 wallet and wait to terminate self.nodes[1].encryptwallet("test") # send node 0 shield addr to note 2 zaddr recipients = [] recipients.append({"address":myzaddr, "amount":7.0}) txid = self.nodes[0].shieldsendmany(myzaddr0, recipients) self.sync_all() self.nodes[0].generate(1) self.sync_all() # check shield addr balance zsendmanynotevalue = Decimal('7.0') assert_equal(self.nodes[2].getshieldbalance(myzaddr), zsendmanynotevalue) assert_equal(self.nodes[1].getshieldbalance(myzaddr), zsendmanynotevalue) # add shield addr to node 3 myzaddr3 = self.nodes[3].getnewshieldaddress() # send node 2 shield addr to note 3 shield addr recipients = [] recipients.append({"address":myzaddr3, "amount":2.0}) txid = self.nodes[2].shieldsendmany(myzaddr, recipients) self.sync_all() self.nodes[2].generate(1) self.sync_all() # check shield addr balance zsendmany2notevalue = Decimal('2.0') zsendmanyfee = Decimal(self.nodes[2].viewshieldtransaction(txid)['fee']) zaddrremaining = zsendmanynotevalue - zsendmany2notevalue - zsendmanyfee assert_equal(self.nodes[3].getshieldbalance(myzaddr3), zsendmany2notevalue) assert_equal(self.nodes[2].getshieldbalance(myzaddr), zaddrremaining) assert_equal(self.nodes[1].getshieldbalance(myzaddr), zaddrremaining) # send node 2 shield addr on node 1 to taddr # This requires that node 1 be unlocked, which triggers caching of # uncached nullifiers. self.nodes[1].walletpassphrase("test", 600) mytaddr1 = self.nodes[1].getnewaddress() recipients = [] recipients.append({"address":mytaddr1, "amount":1.0}) txid = self.nodes[1].shieldsendmany(myzaddr, recipients) self.sync_all() self.nodes[1].generate(1) self.sync_all() # check shield addr balance # Now that the encrypted wallet has been unlocked, the note nullifiers # have been cached and spent notes can be detected. Thus the two wallets # are in agreement once more. zsendmany3notevalue = Decimal('1.0') zsendmanyfee = Decimal(self.nodes[1].viewshieldtransaction(txid)['fee']) zaddrremaining2 = zaddrremaining - zsendmany3notevalue - zsendmanyfee assert_equal(self.nodes[1].getshieldbalance(myzaddr), zaddrremaining2) assert_equal(self.nodes[2].getshieldbalance(myzaddr), zaddrremaining2) # Test viewing keys node3mined = Decimal('6250.0') assert_equal(self.nodes[3].getshieldbalance(), zsendmany2notevalue) assert_equal(self.nodes[3].getbalance(1, False, True, False), node3mined) # Add node 1 address and node 2 viewing key to node 3 myzvkey = self.nodes[2].exportsaplingviewingkey(myzaddr) self.nodes[3].importaddress(mytaddr1) importvk_result = self.nodes[3].importsaplingviewingkey(myzvkey, 'whenkeyisnew', 1) # Check results of importsaplingviewingkey assert_equal(importvk_result["address"], myzaddr) # Check the address has been imported assert_equal(myzaddr in self.nodes[3].listshieldaddresses(), False) assert_equal(myzaddr in self.nodes[3].listshieldaddresses(True), True) # Node 3 should see the same received notes as node 2; however, there are 2 things: # - Some of the notes were change for node 2 but not for node 3. # - Each node wallet store transaction time as received. As # `wait_and_assert_operationid_status` is called node 2 and 3 are off by a few seconds. # Aside from that the received notes should be the same. So, # group by txid and then check that all properties aside from # change are equal. node2Received = dict([r['txid'], r] for r in self.nodes[2].listreceivedbyshieldaddress(myzaddr)) node3Received = dict([r['txid'], r] for r in self.nodes[3].listreceivedbyshieldaddress(myzaddr)) assert_equal(len(node2Received), len(node2Received)) for txid in node2Received: received2 = node2Received[txid] received3 = node3Received[txid] # the change field will be omitted for received3, but all other fields should be shared assert_true(len(received2) >= len(received3)) for key in received2: # check all the properties except for change and blocktime if key != 'change' and key != 'blocktime': assert_equal(received2[key], received3[key]) # Node 3's balances should be unchanged without explicitly requesting # to include watch-only balances assert_equal(self.nodes[3].getshieldbalance(), zsendmany2notevalue) assert_equal(self.nodes[3].getbalance(1, False, True, False), node3mined) assert_equal(self.nodes[3].getshieldbalance("*", 1, True), zsendmany2notevalue + zaddrremaining2) assert_equal(self.nodes[3].getbalance(1, True, True, False), node3mined + Decimal('1.0')) # Check individual balances reflect the above assert_equal(self.nodes[3].getreceivedbyaddress(mytaddr1), Decimal('1.0')) assert_equal(self.nodes[3].getshieldbalance(myzaddr), Decimal('0.0')) assert_equal(self.nodes[3].getshieldbalance(myzaddr, 1, True), zaddrremaining2)
def run_test(self): # generate 100 more to activate sapling in regtest self.nodes[2].generate(12) self.sync_all() self.nodes[0].generate(360) # Sanity-check the test harness assert_equal(self.nodes[0].getblockcount(), 372) taddr1 = self.nodes[1].getnewaddress() saplingAddr0 = self.nodes[0].getnewshieldedaddress() saplingAddr1 = self.nodes[1].getnewshieldedaddress() # Verify addresses assert(saplingAddr0 in self.nodes[0].listshieldedaddresses()) assert(saplingAddr1 in self.nodes[1].listshieldedaddresses()) assert_equal(self.nodes[0].validateaddress(saplingAddr0)['type'], 'sapling') assert_equal(self.nodes[0].validateaddress(saplingAddr1)['type'], 'sapling') # Verify balance assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('0')) assert_equal(self.nodes[1].getshieldedbalance(saplingAddr1), Decimal('0')) assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('0')) # Hardcoded min sapling fee nMinDefaultSaplingFee = 1 # Node 0 shields some funds # taddr -> Sapling recipients = [] recipients.append({"address": saplingAddr0, "amount": Decimal('10')}) coinstake = get_coinstake_address(self.nodes[0]) mytxid = self.nodes[0].shielded_sendmany(coinstake, recipients, 1, nMinDefaultSaplingFee) self.sync_all() # Verify priority of tx is INF_PRIORITY, defined as 1E+25 (10000000000000000000000000) mempool = self.nodes[0].getrawmempool(True) self.check_tx_priority(mempool, mytxid) # Shield another coinbase UTXO mytxid = self.nodes[0].shielded_sendmany(get_coinstake_address(self.nodes[0]), recipients, 1, nMinDefaultSaplingFee) self.sync_all() self.nodes[2].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('20')) assert_equal(self.nodes[1].getshieldedbalance(saplingAddr1), Decimal('0')) assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('0')) # Node 0 sends some shielded funds to node 1 # Sapling -> Sapling # -> Sapling (change) recipients = [] recipients.append({"address": saplingAddr1, "amount": Decimal('15')}) mytxid = self.nodes[0].shielded_sendmany(saplingAddr0, recipients, 1, nMinDefaultSaplingFee) self.sync_all() # Verify priority of tx is MAX_PRIORITY, defined as 1E+25 (10000000000000000000000000) mempool = self.nodes[0].getrawmempool(True) self.check_tx_priority(mempool, mytxid) self.nodes[2].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('4')) # 20 receive - (15 sent + 1 fee) assert_equal(self.nodes[1].getshieldedbalance(saplingAddr1), Decimal('15')) assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('0')) # Node 1 sends some shielded funds to node 0, as well as unshielding # Sapling -> Sapling # -> taddr # -> Sapling (change) recipients = [] recipients.append({"address": saplingAddr0, "amount": Decimal('5')}) recipients.append({"address": taddr1, "amount": Decimal('5')}) mytxid = self.nodes[1].shielded_sendmany(saplingAddr1, recipients, 1, nMinDefaultSaplingFee) self.sync_all() # Verify priority of tx is MAX_PRIORITY, defined as 1E+25 (10000000000000000000000000) mempool = self.nodes[1].getrawmempool(True) self.check_tx_priority(mempool, mytxid) self.nodes[2].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('9')) # 20 receive - (15 sent + 1 fee) + 5 receive assert_equal(self.nodes[1].getshieldedbalance(saplingAddr1), Decimal('4')) assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('5')) # Verify existence of Sapling related JSON fields resp = self.nodes[0].getrawtransaction(mytxid, 1) assert_equal(Decimal(resp['valueBalance']), Decimal('6.00')) # 15 shielded input - 5 shielded spend - 4 change assert(len(resp['vShieldedSpend']) == 1) assert(len(resp['vShieldedOutput']) == 2) assert('bindingSig' in resp) shieldedSpend = resp['vShieldedSpend'][0] assert('cv' in shieldedSpend) assert('anchor' in shieldedSpend) assert('nullifier' in shieldedSpend) assert('rk' in shieldedSpend) assert('proof' in shieldedSpend) assert('spendAuthSig' in shieldedSpend) shieldedOutput = resp['vShieldedOutput'][0] assert('cv' in shieldedOutput) assert('cmu' in shieldedOutput) assert('ephemeralKey' in shieldedOutput) assert('encCiphertext' in shieldedOutput) assert('outCiphertext' in shieldedOutput) assert('proof' in shieldedOutput) # Verify importing a spending key will update the nullifiers and witnesses correctly sk0 = self.nodes[0].exportsaplingkey(saplingAddr0) saplingAddrInfo0 = self.nodes[2].importsaplingkey(sk0, "yes") assert_equal(saplingAddrInfo0["address"], saplingAddr0) assert_equal(self.nodes[2].getshieldedbalance(saplingAddrInfo0["address"]), Decimal('9')) sk1 = self.nodes[1].exportsaplingkey(saplingAddr1) saplingAddrInfo1 = self.nodes[2].importsaplingkey(sk1, "yes") assert_equal(saplingAddrInfo1["address"], saplingAddr1) assert_equal(self.nodes[2].getshieldedbalance(saplingAddrInfo1["address"]), Decimal('4')) # Verify importing a viewing key will update the nullifiers and witnesses correctly extfvk0 = self.nodes[0].exportsaplingviewingkey(saplingAddr0) saplingAddrInfo0 = self.nodes[3].importsaplingviewingkey(extfvk0, "yes") assert_equal(saplingAddrInfo0["address"], saplingAddr0) assert_equal(Decimal(self.nodes[3].getshieldedbalance(saplingAddrInfo0["address"], 1, True)), Decimal('9')) extfvk1 = self.nodes[1].exportsaplingviewingkey(saplingAddr1) saplingAddrInfo1 = self.nodes[3].importsaplingviewingkey(extfvk1, "yes") assert_equal(saplingAddrInfo1["address"], saplingAddr1) assert_equal(self.nodes[3].getshieldedbalance(saplingAddrInfo1["address"], 1, True), Decimal('4')) # Verify that getshieldedbalance only includes watch-only addresses when requested shieldedBalance = self.nodes[3].getshieldedbalance() # no balance in the wallet assert_equal(shieldedBalance, Decimal('0')) shieldedBalance = self.nodes[3].getshieldedbalance("*", 1, True) # watch only balance assert_equal(shieldedBalance, Decimal('13.00'))
def run_test(self): self.nodes[0].generate( 4) # generate blocks to activate sapling in regtest # verify sapling activation. assert (self.nodes[0].getblockchaininfo()['upgrades']['v5 shield'] ['activationheight'] == 1) self.sync_all() walletinfo = self.nodes[0].getwalletinfo() assert_equal(self.nodes[0].getblockcount(), walletinfo['last_processed_block']) assert_equal(walletinfo['immature_balance'], 1000) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[1].generate(102) self.sync_all() assert_equal(self.nodes[0].getbalance(), 1000) assert_equal(self.nodes[1].getbalance(), 500) assert_equal(self.nodes[2].getbalance(), 0) # At this point in time, commitment tree is the empty root # Node 0 creates a shield transaction mytaddr0 = get_coinstake_address(self.nodes[0]) myzaddr0 = self.nodes[0].getnewshieldaddress() recipients = [] recipients.append({ "address": myzaddr0, "amount": Decimal('10.0') - Decimal('0.0001') }) txid = self.nodes[0].shieldsendmany(mytaddr0, recipients) # Sync up mempools and mine the transaction. All nodes have the same anchor. self.sync_all() self.nodes[0].generate(1) self.sync_all() # Stop nodes. self.stop_nodes() # Relaunch nodes and partition network into two: # A: node 0 # B: node 1, 2 self.start_node(0, self.extra_args[0]) self.start_node(1, self.extra_args[1]) self.start_node(2, self.extra_args[2]) connect_nodes(self.nodes[1], 2) # Partition B, node 1 mines an empty block self.nodes[1].generate(1) self.sync_blocks(self.nodes[1:3]) # Check partition assert_equal(self.nodes[1].getblockcount(), self.nodes[2].getblockcount()) assert (self.nodes[2].getblockcount() != self.nodes[0].getblockcount()) # Partition A, node 0 creates a shield transaction recipients = [] recipients.append({ "address": myzaddr0, "amount": Decimal('10.0') - Decimal('0.0001') }) txid = self.nodes[0].shieldsendmany(mytaddr0, recipients) rawhex = self.nodes[0].getrawtransaction(txid) # Partition A, node 0 mines a block with the transaction self.nodes[0].generate(1) self.sync_all(self.nodes[1:3]) # Partition B, node 1 mines the same shield transaction txid2 = self.nodes[1].sendrawtransaction(rawhex) assert_equal(txid, txid2) self.nodes[1].generate(1) # Check that Partition B is one block ahead and that they have different tips assert_equal(self.nodes[0].getblockcount() + 1, self.nodes[1].getblockcount()) assert (self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash()) # Shut down all nodes so any in-memory state is saved to disk self.stop_nodes() # Relaunch nodes and reconnect the entire network self.start_nodes() connect_nodes(self.nodes[0], 1) connect_nodes(self.nodes[2], 1) connect_nodes(self.nodes[2], 0) # Mine a new block and let it propagate self.nodes[1].generate(1) self.sync_all() assert_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash()) assert_equal(self.nodes[1].getbestblockhash(), self.nodes[2].getbestblockhash())
def run_test(self): self.log.info("Mining 120 blocks...") self.nodes[0].generate(120) self.sync_all() # Sanity-check the test harness assert_equal([x.getblockcount() for x in self.nodes], [120] * self.num_nodes) taddr1 = self.nodes[1].getnewaddress() saplingAddr0 = self.nodes[0].getnewshieldedaddress() saplingAddr1 = self.nodes[1].getnewshieldedaddress() # Verify addresses assert (saplingAddr0 in self.nodes[0].listshieldedaddresses()) assert (saplingAddr1 in self.nodes[1].listshieldedaddresses()) assert_equal(self.nodes[0].validateaddress(saplingAddr0)['type'], 'sapling') assert_equal(self.nodes[0].validateaddress(saplingAddr1)['type'], 'sapling') # Verify balance assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('0')) assert_equal(self.nodes[1].getshieldedbalance(saplingAddr1), Decimal('0')) assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('0')) # Fixed fee fee = 1 # Node 0 shields some funds # taddr -> Sapling self.log.info("TX 1: shield funds from specified transparent address.") recipients = [{"address": saplingAddr0, "amount": Decimal('10')}] mytxid1 = self.nodes[0].shieldedsendmany( get_coinstake_address(self.nodes[0]), recipients, 1, fee) # shield more funds automatically selecting the transparent inputs self.log.info("TX 2: shield funds from any transparent address.") mytxid2 = self.nodes[0].shieldedsendmany("from_transparent", recipients, 1, fee) # shield more funds creating and then sending a raw transaction self.log.info( "TX 3: shield funds creating and sending raw transaction.") tx_json = self.nodes[0].rawshieldedsendmany("from_transparent", recipients, 1, fee) mytxid3 = self.nodes[0].sendrawtransaction(tx_json["hex"]) # Verify priority of tx is INF_PRIORITY, defined as 1E+25 (10000000000000000000000000) self.check_tx_priority([mytxid1, mytxid2, mytxid3]) self.log.info("Priority for tx1, tx2 and tx3 checks out") self.nodes[2].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('30')) assert_equal(self.nodes[1].getshieldedbalance(saplingAddr1), Decimal('0')) assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('0')) self.log.info("Balances check out") # Node 0 sends some shielded funds to node 1 # Sapling -> Sapling # -> Sapling (change) self.log.info( "TX 4: shielded transaction from specified sapling address.") recipients4 = [{"address": saplingAddr1, "amount": Decimal('10')}] mytxid4 = self.nodes[0].shieldedsendmany(saplingAddr0, recipients4, 1, fee) self.check_tx_priority([mytxid4]) self.nodes[2].generate(1) self.sync_all() # Send more shielded funds (this time with automatic selection of the source) self.log.info("TX 5: shielded transaction from any sapling address.") recipients5 = [{"address": saplingAddr1, "amount": Decimal('5')}] mytxid5 = self.nodes[0].shieldedsendmany("from_shielded", recipients5, 1, fee) self.check_tx_priority([mytxid5]) self.nodes[2].generate(1) self.sync_all() # Send more shielded funds (with create + send raw transaction) self.log.info("TX 6: shielded raw transaction.") tx_json = self.nodes[0].rawshieldedsendmany("from_shielded", recipients5, 1, fee) mytxid6 = self.nodes[0].sendrawtransaction(tx_json["hex"]) self.check_tx_priority([mytxid6]) self.nodes[2].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('7')) # 30 received - (20 sent + 3 fee) assert_equal(self.nodes[1].getshieldedbalance(saplingAddr1), Decimal('20')) # 20 received assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('0')) self.log.info("Balances check out") # Node 1 sends some shielded funds to node 0, as well as unshielding # Sapling -> Sapling # -> taddr # -> Sapling (change) self.log.info("TX 7: deshield funds from specified sapling address.") recipients7 = [{"address": saplingAddr0, "amount": Decimal('8')}] recipients7.append({"address": taddr1, "amount": Decimal('10')}) mytxid7 = self.nodes[1].shieldedsendmany(saplingAddr1, recipients7, 1, fee) self.check_tx_priority([mytxid7]) self.nodes[2].generate(1) self.sync_all() # Verify balance assert_equal(self.nodes[0].getshieldedbalance(saplingAddr0), Decimal('15')) # 7 prev balance + 8 received assert_equal(self.nodes[1].getshieldedbalance(saplingAddr1), Decimal('1')) # 20 prev balance - (18 sent + 1 fee) assert_equal(self.nodes[1].getreceivedbyaddress(taddr1), Decimal('10')) self.log.info("Balances check out") # Verify existence of Sapling related JSON fields resp = self.nodes[0].getrawtransaction(mytxid7, 1) assert_equal(Decimal(resp['valueBalance']), Decimal( '11.00')) # 20 shielded input - 8 shielded spend - 1 change assert_equal(len(resp['vShieldedSpend']), 3) assert_equal(len(resp['vShieldedOutput']), 2) assert ('bindingSig' in resp) shieldedSpend = resp['vShieldedSpend'][0] assert ('cv' in shieldedSpend) assert ('anchor' in shieldedSpend) assert ('nullifier' in shieldedSpend) assert ('rk' in shieldedSpend) assert ('proof' in shieldedSpend) assert ('spendAuthSig' in shieldedSpend) shieldedOutput = resp['vShieldedOutput'][0] assert ('cv' in shieldedOutput) assert ('cmu' in shieldedOutput) assert ('ephemeralKey' in shieldedOutput) assert ('encCiphertext' in shieldedOutput) assert ('outCiphertext' in shieldedOutput) assert ('proof' in shieldedOutput) self.log.info("Raw transaction decoding checks out") # Verify importing a spending key will update the nullifiers and witnesses correctly self.log.info("Checking exporting/importing a spending key...") sk0 = self.nodes[0].exportsaplingkey(saplingAddr0) saplingAddrInfo0 = self.nodes[2].importsaplingkey(sk0, "yes") assert_equal(saplingAddrInfo0["address"], saplingAddr0) assert_equal( self.nodes[2].getshieldedbalance(saplingAddrInfo0["address"]), Decimal('15')) sk1 = self.nodes[1].exportsaplingkey(saplingAddr1) saplingAddrInfo1 = self.nodes[2].importsaplingkey(sk1, "yes") assert_equal(saplingAddrInfo1["address"], saplingAddr1) assert_equal( self.nodes[2].getshieldedbalance(saplingAddrInfo1["address"]), Decimal('1')) # Verify importing a viewing key will update the nullifiers and witnesses correctly self.log.info("Checking exporting/importing a viewing key...") extfvk0 = self.nodes[0].exportsaplingviewingkey(saplingAddr0) saplingAddrInfo0 = self.nodes[3].importsaplingviewingkey( extfvk0, "yes") assert_equal(saplingAddrInfo0["address"], saplingAddr0) assert_equal( Decimal(self.nodes[3].getshieldedbalance( saplingAddrInfo0["address"], 1, True)), Decimal('15')) extfvk1 = self.nodes[1].exportsaplingviewingkey(saplingAddr1) saplingAddrInfo1 = self.nodes[3].importsaplingviewingkey( extfvk1, "yes") assert_equal(saplingAddrInfo1["address"], saplingAddr1) assert_equal( self.nodes[3].getshieldedbalance(saplingAddrInfo1["address"], 1, True), Decimal('1')) # no balance in the wallet assert_equal(self.nodes[3].getshieldedbalance(), Decimal('0')) # watch only balance assert_equal(self.nodes[3].getshieldedbalance("*", 1, True), Decimal('16.00')) self.log.info("All good.")