mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-15 12:51:00 +02:00
Add assets and issuance functional tests
This commit is contained in:
parent
96af43b185
commit
a687dd9a34
4 changed files with 669 additions and 0 deletions
70
test/functional/feature_assetsdir.py
Executable file
70
test/functional/feature_assetsdir.py
Executable file
|
|
@ -0,0 +1,70 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#
|
||||
# Test use of assetdir to locally label assets.
|
||||
# Test listissuances returns a list of all issuances or specific issuances based on asset hex or asset label.
|
||||
#
|
||||
|
||||
from decimal import Decimal
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.authproxy import JSONRPCException
|
||||
from test_framework.util import assert_equal, assert_greater_than
|
||||
from test_framework.util import *
|
||||
|
||||
class AssetdirTests(BitcoinTestFramework):
|
||||
"""
|
||||
Test use of assetdir to specify asset labels.
|
||||
Test listissuances returns a list of all issuances or specific issuances based on asset hex or asset label.
|
||||
"""
|
||||
|
||||
def set_test_params(self):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
[["-initialfreecoins=2100000000000000", "-anyonecanspendaremine=1", "-con_connect_coinbase=1", "-con_blocksubsidy=0"]]
|
||||
|
||||
def setup_network(self, split=False):
|
||||
self.setup_nodes()
|
||||
|
||||
def run_test(self):
|
||||
self.nodes[0].generate(101)
|
||||
|
||||
#Issue two assets that we will later label using the assetdir parameter
|
||||
issuance1 = self.nodes[0].issueasset(100, 1, False)
|
||||
asset1hex = issuance1["asset"]
|
||||
|
||||
issuance2 = self.nodes[0].issueasset(100, 1, False)
|
||||
asset2hex = issuance2["asset"]
|
||||
|
||||
#Stop and restart the nodes, providing the assetdir parameter to locally label the assets
|
||||
self.stop_nodes()
|
||||
self.start_nodes([["-assetdir=" + asset1hex + ":asset1", "-assetdir=" + asset2hex + ":asset2"]])
|
||||
|
||||
#Check that listissuances return all issuances
|
||||
issuances = self.nodes[0].listissuances()
|
||||
assert_equal(len(issuances), 2)
|
||||
|
||||
#Check all asset labels have been set: 'asset1', 'asset2'
|
||||
#We can not be sure they will always be returned in the same order so will loop each one
|
||||
label = ""
|
||||
for issue in issuances:
|
||||
label += issue["assetlabel"]
|
||||
|
||||
assert_greater_than(label.find("asset1"), -1)
|
||||
assert_greater_than(label.find("asset2"), -1)
|
||||
|
||||
#Check we can get a list of isuances for a given label
|
||||
issuances = self.nodes[0].listissuances("asset1")
|
||||
assert_equal(len(issuances), 1)
|
||||
assert_equal(issuances[0]["assetlabel"], "asset1")
|
||||
|
||||
#Check we can get a list of issuances for a given hex
|
||||
issuances = self.nodes[0].listissuances(asset2hex)
|
||||
assert_equal(len(issuances), 1)
|
||||
assert_equal(issuances[0]["assetlabel"], "asset2")
|
||||
|
||||
if __name__ == '__main__':
|
||||
AssetdirTests().main()
|
||||
|
||||
70
test/functional/feature_default_asset_name.py
Executable file
70
test/functional/feature_default_asset_name.py
Executable file
|
|
@ -0,0 +1,70 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#
|
||||
# Test chain initialisation when specifying default asset name.
|
||||
#
|
||||
|
||||
from decimal import Decimal
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.authproxy import JSONRPCException
|
||||
from test_framework.util import assert_equal, connect_nodes_bi
|
||||
|
||||
class NamedDefaultAssetTest(BitcoinTestFramework):
|
||||
"""
|
||||
Test creation of default asset is named according to defaultpeggedasset parameter
|
||||
|
||||
"""
|
||||
|
||||
def set_test_params(self):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 2
|
||||
|
||||
#Set default asset name
|
||||
self.extra_args = [["-defaultpeggedassetname=testasset", "-initialfreecoins=2100000000000000", "-anyonecanspendaremine=1", "-con_connect_coinbase=1", "-con_blocksubsidy=0"]]*2
|
||||
|
||||
def setup_network(self, split=False):
|
||||
self.setup_nodes()
|
||||
connect_nodes_bi(self.nodes, 0, 1)
|
||||
self.is_network_split = False
|
||||
self.sync_all()
|
||||
|
||||
def run_test(self):
|
||||
#Claim all anyone-can-spend coins and test that calling sendtoaddress without providing the assetlabel parameter results in the specified default pegged asset being sent.
|
||||
self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 21000000, "", "", True)
|
||||
self.nodes[0].generate(101)
|
||||
self.sync_all()
|
||||
|
||||
#Check the default asset is named correctly
|
||||
walletinfo1 = self.nodes[0].getwalletinfo()
|
||||
assert_equal(walletinfo1["balance"]["testasset"], 21000000)
|
||||
|
||||
#Send some of the default asset to the second node
|
||||
self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1, "", "", False)
|
||||
self.nodes[0].generate(101)
|
||||
self.sync_all()
|
||||
|
||||
#Check balances are correct and asset is named correctly
|
||||
walletinfo1 = self.nodes[0].getwalletinfo()
|
||||
assert_equal(walletinfo1["balance"]["testasset"], 20999999)
|
||||
|
||||
walletinfo2 = self.nodes[1].getwalletinfo()
|
||||
assert_equal(walletinfo2["balance"]["testasset"], 1)
|
||||
|
||||
#Check we send the default 'testasset' when calling 'sendmany' without needing to provide the relevant asset label
|
||||
outputs = {self.nodes[1].getnewaddress(): 1.0, self.nodes[1].getnewaddress(): 3.0}
|
||||
self.nodes[0].sendmany("", outputs)
|
||||
self.nodes[0].generate(101)
|
||||
self.sync_all()
|
||||
|
||||
#Check balances are correct and asset is named correctly
|
||||
walletinfo1 = self.nodes[0].getwalletinfo()
|
||||
assert_equal(walletinfo1["balance"]["testasset"], 20999995)
|
||||
|
||||
walletinfo2 = self.nodes[1].getwalletinfo()
|
||||
assert_equal(walletinfo2["balance"]["testasset"], 5)
|
||||
|
||||
if __name__ == '__main__':
|
||||
NamedDefaultAssetTest().main()
|
||||
87
test/functional/feature_initial_reissuance_token.py
Executable file
87
test/functional/feature_initial_reissuance_token.py
Executable file
|
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#
|
||||
# Test chain initialisation when specifying number of reissuance tokens to issue.
|
||||
#
|
||||
|
||||
from decimal import Decimal
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.authproxy import JSONRPCException
|
||||
from test_framework.util import connect_nodes_bi, assert_equal
|
||||
from test_framework.util import *
|
||||
|
||||
class InitialReissuanceTokenTest(BitcoinTestFramework):
|
||||
"""
|
||||
Test creation of initial reissuance token for default asset on chain set up
|
||||
|
||||
"""
|
||||
|
||||
def set_test_params(self):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 2
|
||||
|
||||
#Set number of initial reissuance tokens and also set initial free coins less than max so we can reissue more later
|
||||
self.extra_args = [["-initialreissuancetokens=200000000", "-initialfreecoins=2000000000000000", "-anyonecanspendaremine=1", "-con_connect_coinbase=1", "-con_blocksubsidy=0", "-blindedaddresses=1"]]*2
|
||||
|
||||
def setup_network(self, split=False):
|
||||
self.setup_nodes()
|
||||
connect_nodes_bi(self.nodes, 0, 1)
|
||||
self.is_network_split = False
|
||||
self.sync_all()
|
||||
|
||||
def run_test(self):
|
||||
self.nodes[0].generate(101)
|
||||
self.sync_all()
|
||||
|
||||
walletinfo = self.nodes[0].getwalletinfo()
|
||||
balance = walletinfo['balance']
|
||||
token = ""
|
||||
|
||||
#Get the hex of the reissuance token
|
||||
for i in balance:
|
||||
token = i
|
||||
if token != "bitcoin":
|
||||
break
|
||||
|
||||
# Claim all anyone-can-spend reissuance tokens, which also blinds the token output
|
||||
# which is required for re-issuance: https://github.com/ElementsProject/elements/issues/259
|
||||
self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2, "", "", False, False, 6, "UNSET", token)
|
||||
self.nodes[0].generate(101)
|
||||
self.sync_all()
|
||||
|
||||
#Check balances
|
||||
walletinfo1 = self.nodes[0].getwalletinfo()
|
||||
assert_equal(walletinfo1["balance"]["bitcoin"], 20000000)
|
||||
assert_equal(walletinfo1["balance"][token], 2)
|
||||
|
||||
#Reissue some of the default asset
|
||||
self.nodes[0].reissueasset("bitcoin", 1234)
|
||||
self.nodes[0].generate(101)
|
||||
self.sync_all()
|
||||
|
||||
#Check the reissuance worked
|
||||
walletinfo1 = self.nodes[0].getwalletinfo()
|
||||
assert_equal(walletinfo1["balance"]["bitcoin"], 20001234)
|
||||
|
||||
#Send some 'bitcoin' to node 2 so they can fund a reissuance transaction
|
||||
self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1, "", "", False)
|
||||
|
||||
#Send a reissuance token to node 2 so they can reissue the default asset
|
||||
self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1, "", "", False, False, 6, "UNSET", token)
|
||||
self.nodes[0].generate(101)
|
||||
self.sync_all()
|
||||
|
||||
#Reissue some of the default asset
|
||||
self.nodes[1].reissueasset("bitcoin", 1000)
|
||||
self.nodes[1].generate(101)
|
||||
self.sync_all()
|
||||
|
||||
#Check balance is the 1 'bitcoin' sent from node 1 plus the 1000 'bitcoin' reissued by node 2
|
||||
walletinfo2 = self.nodes[1].getwalletinfo()
|
||||
assert_equal(walletinfo2["balance"]["bitcoin"], 1001)
|
||||
|
||||
if __name__ == '__main__':
|
||||
InitialReissuanceTokenTest().main()
|
||||
442
test/functional/feature_issuance.py
Executable file
442
test/functional/feature_issuance.py
Executable file
|
|
@ -0,0 +1,442 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2016 The Bitcoin Core developers
|
||||
# Distributed under the MIT/X11 software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import assert_equal, assert_greater_than_or_equal, assert_raises_rpc_error, connect_nodes_bi
|
||||
from test_framework.authproxy import JSONRPCException
|
||||
from decimal import Decimal
|
||||
|
||||
" Tests issued assets functionality including (re)issuance, and de-issuance "
|
||||
|
||||
# Creates a raw issuance transaction based on the passed in list, checking important details after
|
||||
def process_raw_issuance(node, issuance_list):
|
||||
if len(issuance_list) > 5:
|
||||
raise Exception('Issuance list too long')
|
||||
# Make enough outputs for any subsequent spend
|
||||
next_destinations = {}
|
||||
output_values = (node.getbalance()['bitcoin']-1)/5
|
||||
for i in range(5):
|
||||
next_destinations[node.getnewaddress()] = output_values
|
||||
|
||||
raw_tx = node.createrawtransaction([], next_destinations)
|
||||
# We "over-fund" these transactions to 50 sat/vbyte since issuances aren't baked in yet
|
||||
# Otherwise huge multi-issuances may fail min-relay
|
||||
funded_tx = node.fundrawtransaction(raw_tx, {"feeRate":Decimal('0.00050000')})['hex']
|
||||
issued_call_details = node.rawissueasset(funded_tx, issuance_list)
|
||||
issued_tx = issued_call_details[-1]["hex"] # Get hex from end
|
||||
# don't accept blinding fail, and blind all issuances or none at all
|
||||
blind_tx = node.blindrawtransaction(issued_tx, False, [], issuance_list[0]["blind"])
|
||||
signed_tx = node.signrawtransactionwithwallet(blind_tx)
|
||||
tx_id = node.sendrawtransaction(signed_tx['hex'])
|
||||
node.generate(1)
|
||||
assert_equal(node.gettransaction(tx_id)["confirmations"], 1)
|
||||
num_issuance = 0
|
||||
decoded_tx = node.decoderawtransaction(signed_tx['hex'])
|
||||
decoded_unblind_tx = node.decoderawtransaction(issued_tx)
|
||||
for i, (issuance_req, tx_input, issuance_result) in enumerate(zip(issuance_list, decoded_tx["vin"], issued_call_details)):
|
||||
if "issuance" not in tx_input:
|
||||
break
|
||||
|
||||
num_issuance += 1
|
||||
issuance_details = tx_input["issuance"]
|
||||
if "blind" not in issuance_req or issuance_req["blind"] == True:
|
||||
|
||||
assert("assetamount" not in issuance_details)
|
||||
assert("tokenamount" not in issuance_details)
|
||||
assert_equal(issuance_details["assetBlindingNonce"], "00"*32)
|
||||
if "asset_amount" in issuance_req:
|
||||
assert("assetamountcommitment" in issuance_details)
|
||||
if "token_amount" in issuance_req:
|
||||
assert("tokenamountcommitment" in issuance_details)
|
||||
else:
|
||||
if "asset_amount" in issuance_req:
|
||||
assert_equal(issuance_details["assetamount"], issuance_req["asset_amount"])
|
||||
if "token_amount" in issuance_req:
|
||||
assert_equal(issuance_details["tokenamount"], issuance_req["token_amount"])
|
||||
|
||||
# Cross-check RPC call result details with raw details
|
||||
assert_equal(issuance_result["vin"], i)
|
||||
assert_equal(issuance_result["entropy"], issuance_details["assetEntropy"])
|
||||
if "asset" in issuance_details:
|
||||
assert_equal(issuance_result["asset"], issuance_details["asset"])
|
||||
if "token" in issuance_details:
|
||||
assert_equal(issuance_result["token"], issuance_details["token"])
|
||||
|
||||
# Look for outputs assets where we expect them, or not, initial issuance first then token
|
||||
for issuance_type in ["asset", "token"]:
|
||||
blind_dest = issuance_type+"_address" not in issuance_req or node.validateaddress(issuance_req[issuance_type+"_address"])["confidential_key"] != ""
|
||||
if blind_dest:
|
||||
# We should not find any the issuances we made since the addresses confidential
|
||||
for output in decoded_tx["vout"]:
|
||||
if "asset" in output and output["asset"] == issuance_details[issuance_type]:
|
||||
raise Exception("Found asset in plaintext that should be confidential!")
|
||||
|
||||
# Now scan unblinded version of issuance outputs
|
||||
asset_found = False
|
||||
for output in decoded_unblind_tx["vout"]:
|
||||
if "asset" in output and output["asset"] == issuance_details[issuance_type]:
|
||||
if issuance_type+"_address" not in issuance_req:
|
||||
raise Exception("Found asset type not requested")
|
||||
if "value" in output and \
|
||||
output["value"] == issuance_req[issuance_type+"_amount"]:
|
||||
asset_found = True
|
||||
|
||||
# Find the asset type if it was created
|
||||
assert(asset_found if issuance_type+"_address" in issuance_req else True)
|
||||
|
||||
assert_equal(num_issuance, len(issuance_list))
|
||||
|
||||
class IssuanceTest(BitcoinTestFramework):
|
||||
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 3
|
||||
self.extra_args = [["-blindedaddresses=1"]] * self.num_nodes
|
||||
self.setup_clean_chain = True
|
||||
|
||||
def setup_network(self, split=False):
|
||||
self.setup_nodes()
|
||||
connect_nodes_bi(self.nodes, 0, 1)
|
||||
connect_nodes_bi(self.nodes, 1, 2)
|
||||
self.is_network_split = False
|
||||
self.sync_all()
|
||||
|
||||
def run_test(self):
|
||||
self.nodes[0].generate(105)
|
||||
# Make sure test starts with no initial issuance.
|
||||
assert_equal(len(self.nodes[0].listissuances()), 0);
|
||||
|
||||
# Unblinded issuance of asset
|
||||
issued = self.nodes[0].issueasset(1, 1, False)
|
||||
balance = self.nodes[0].getwalletinfo()["balance"]
|
||||
assert_equal(balance[issued["asset"]], 1)
|
||||
assert_equal(balance[issued["token"]], 1)
|
||||
# Quick unblinded reissuance check, making 2*COIN total
|
||||
self.nodes[0].reissueasset(issued["asset"], 1)
|
||||
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
issued2 = self.nodes[0].issueasset(2, 1)
|
||||
test_asset = issued2["asset"]
|
||||
assert_equal(self.nodes[0].getwalletinfo()['balance'][test_asset], Decimal(2))
|
||||
node1balance = self.nodes[1].getwalletinfo()['balance']
|
||||
if test_asset in node1balance:
|
||||
assert_equal(node1balance[test_asset], Decimal(0))
|
||||
|
||||
# Send bitcoin to node 1 and then from 1 to 2 to force node 1 to
|
||||
# spend confidential money.
|
||||
self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 4)
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
self.nodes[1].sendtoaddress(self.nodes[2].getnewaddress(), 3, "", "", False, False, 1, "UNSET", "", False)
|
||||
self.sync_all()
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
# Destroy assets
|
||||
pre_destroy_btc_balance = self.nodes[2].getwalletinfo()['balance']['bitcoin']
|
||||
self.nodes[2].destroyamount('bitcoin', 2) # Destroy 2 BTC
|
||||
self.nodes[2].generate(1)
|
||||
self.sync_all()
|
||||
assert_greater_than_or_equal(pre_destroy_btc_balance - Decimal('2'), self.nodes[2].getbalance()['bitcoin'])
|
||||
|
||||
issuedamount = self.nodes[0].getwalletinfo()['balance'][issued["token"]]
|
||||
assert_equal(issuedamount, Decimal('1.0'))
|
||||
self.nodes[0].destroyamount(issued["token"], issuedamount) # Destroy all reissuance tokens of one type
|
||||
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
assert(issued["token"] not in self.nodes[0].getwalletinfo()['balance'])
|
||||
|
||||
# Test various issuance and auditing paths
|
||||
|
||||
issuancedata = self.nodes[0].issueasset(Decimal('0.00000002'), Decimal('0.00000001')) #2 of asset, 1 reissuance token
|
||||
self.nodes[1].generate(1)
|
||||
self.sync_all()
|
||||
assert_equal(self.nodes[0].getwalletinfo()["balance"][issuancedata["asset"]], Decimal('0.00000002'))
|
||||
assert_equal(self.nodes[0].getwalletinfo()["balance"][issuancedata["token"]], Decimal('0.00000001'))
|
||||
self.nodes[0].reissueasset(issuancedata["asset"], Decimal('0.00000001'))
|
||||
self.sync_all()
|
||||
assert_equal(self.nodes[0].getwalletinfo()["balance"][issuancedata["asset"]], Decimal('0.00000003'))
|
||||
# Can't reissue an issuance token (yet)
|
||||
try:
|
||||
self.nodes[0].reissueasset(issuancedata["token"], Decimal('0.00000001'))
|
||||
raise AssertionError("You shouldn't be able to reissue a token yet")
|
||||
except JSONRPCException:
|
||||
pass
|
||||
|
||||
|
||||
issuancedata = self.nodes[2].issueasset(Decimal('0.00000005'), 0) #5 of asset, 0 reissuance token
|
||||
# No reissuance tokens
|
||||
try:
|
||||
self.nodes[2].reissueasset(issuancedata["token"], 5)
|
||||
raise AssertionError("You shouldn't be able to reissue without a token")
|
||||
except JSONRPCException:
|
||||
pass
|
||||
|
||||
issuancedata = self.nodes[2].issueasset(0, Decimal('0.00000006')) #0 of asset, 6 reissuance token
|
||||
|
||||
# Node 2 will send node 1 a reissuance token, both will generate assets
|
||||
self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), Decimal('0.00000001'), "", "", False, False, 1, "UNSET", issuancedata["token"])
|
||||
# node 1 needs to know about a (re)issuance to reissue itself
|
||||
self.nodes[1].importaddress(self.nodes[2].gettransaction(issuancedata["txid"])["details"][0]["address"])
|
||||
# also send some bitcoin
|
||||
self.nodes[2].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
assert_equal(self.nodes[2].getwalletinfo()["balance"][issuancedata["token"]], Decimal('0.00000005'))
|
||||
assert_equal(self.nodes[1].getwalletinfo()["balance"][issuancedata["token"]], Decimal('0.00000001'))
|
||||
redata1 = self.nodes[1].reissueasset(issuancedata["asset"], Decimal('0.05'))
|
||||
redata2 = self.nodes[2].reissueasset(issuancedata["asset"], Decimal('0.025'))
|
||||
|
||||
self.sync_all()
|
||||
# Watch-only issuances won't show up in wallet until confirmed
|
||||
self.nodes[1].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
# Now have node 0 audit these issuances
|
||||
blindingkey1 = self.nodes[1].dumpissuanceblindingkey(redata1["txid"], redata1["vin"])
|
||||
blindingkey2 = self.nodes[2].dumpissuanceblindingkey(redata2["txid"], redata2["vin"])
|
||||
blindingkey3 = self.nodes[2].dumpissuanceblindingkey(issuancedata["txid"], issuancedata["vin"])
|
||||
|
||||
# Need addr to get transactions in wallet. TODO: importissuances?
|
||||
txdet1 = self.nodes[1].gettransaction(redata1["txid"])["details"]
|
||||
txdet2 = self.nodes[2].gettransaction(redata2["txid"])["details"]
|
||||
txdet3 = self.nodes[2].gettransaction(issuancedata["txid"])["details"]
|
||||
|
||||
# Receive addresses added last
|
||||
addr1 = txdet1[len(txdet1)-1]["address"]
|
||||
addr2 = txdet2[len(txdet2)-1]["address"]
|
||||
addr3 = txdet3[len(txdet3)-1]["address"]
|
||||
|
||||
assert_equal(len(self.nodes[0].listissuances()), 5);
|
||||
self.nodes[0].importaddress(addr1)
|
||||
self.nodes[0].importaddress(addr2)
|
||||
self.nodes[0].importaddress(addr3)
|
||||
|
||||
issuances = self.nodes[0].listissuances()
|
||||
assert_equal(len(issuances), 8)
|
||||
|
||||
for issue in issuances:
|
||||
if issue['txid'] == redata1["txid"] and issue['vin'] == redata1["vin"]:
|
||||
assert_equal(issue['assetamount'], Decimal('-1'))
|
||||
if issue['txid'] == redata2["txid"] and issue['vin'] == redata2["vin"]:
|
||||
assert_equal(issue['assetamount'], Decimal('-1'))
|
||||
if issue['txid'] == issuancedata["txid"] and issue['vin'] == issuancedata["vin"]:
|
||||
assert_equal(issue['assetamount'], Decimal('-1'))
|
||||
assert_equal(issue['tokenamount'], Decimal('-1'))
|
||||
|
||||
# Test that importing the issuance blinding keys then reveals the issuance amounts
|
||||
self.nodes[0].importissuanceblindingkey(redata1["txid"], redata1["vin"], blindingkey1)
|
||||
self.nodes[0].importissuanceblindingkey(redata2["txid"], redata2["vin"], blindingkey2)
|
||||
self.nodes[0].importissuanceblindingkey(issuancedata["txid"], issuancedata["vin"], blindingkey3)
|
||||
|
||||
issuances = self.nodes[0].listissuances()
|
||||
|
||||
for issue in issuances:
|
||||
if issue['txid'] == redata1["txid"] and issue['vin'] == redata1["vin"]:
|
||||
assert_equal(issue['assetamount'], Decimal('0.05'))
|
||||
if issue['txid'] == redata2["txid"] and issue['vin'] == redata2["vin"]:
|
||||
assert_equal(issue['assetamount'], Decimal('0.025'))
|
||||
if issue['txid'] == issuancedata["txid"] and issue['vin'] == issuancedata["vin"]:
|
||||
assert_equal(issue['assetamount'], Decimal('0'))
|
||||
assert_equal(issue['tokenamount'], Decimal('0.00000006'))
|
||||
|
||||
# Check for value accounting when asset issuance is null but token not, ie unblinded
|
||||
issued = self.nodes[0].issueasset(0, 1, False)
|
||||
assert(issued["asset"] not in self.nodes[0].getwalletinfo()["balance"])
|
||||
assert_equal(self.nodes[0].getwalletinfo()["balance"][issued["token"]], 1)
|
||||
|
||||
|
||||
print("Raw issuance tests")
|
||||
# Addresses to send to to check proper blinding
|
||||
blind_addr = self.nodes[0].getnewaddress()
|
||||
nonblind_addr = self.nodes[0].validateaddress(blind_addr)['unconfidential']
|
||||
|
||||
# Fail making non-witness issuance sourcing a single unblinded output.
|
||||
# See: https://github.com/ElementsProject/elements/issues/473
|
||||
total_amount = self.nodes[0].getbalance()['bitcoin']
|
||||
self.nodes[0].sendtoaddress(nonblind_addr, total_amount, "", "", True)
|
||||
self.nodes[1].generate(1)
|
||||
raw_tx = self.nodes[0].createrawtransaction([], {nonblind_addr: 1})
|
||||
funded_tx = self.nodes[0].fundrawtransaction(raw_tx)['hex']
|
||||
issued_tx = self.nodes[2].rawissueasset(funded_tx, [{"asset_amount":1, "asset_address":nonblind_addr, "blind":False}])[0]["hex"]
|
||||
blind_tx = self.nodes[0].blindrawtransaction(issued_tx) # This is a no-op
|
||||
signed_tx = self.nodes[0].signrawtransactionwithwallet(blind_tx)
|
||||
assert_raises_rpc_error(-26, "", self.nodes[0].sendrawtransaction, signed_tx['hex'])
|
||||
|
||||
# Make single blinded output to ensure we work around above issue
|
||||
total_amount = self.nodes[0].getbalance()['bitcoin']
|
||||
self.nodes[0].sendtoaddress(blind_addr, total_amount, "", "", True)
|
||||
self.nodes[1].generate(1)
|
||||
|
||||
# Start with single issuance input, unblinded (makes 5 outputs for later larger issuances)
|
||||
process_raw_issuance(self.nodes[0], [{"asset_amount": 2, "asset_address": nonblind_addr, "blind": False}])
|
||||
process_raw_issuance(self.nodes[0], [{"asset_amount": 2, "asset_address": nonblind_addr, "blind": True}])
|
||||
process_raw_issuance(self.nodes[0], [{"token_amount": 5, "token_address": nonblind_addr, "blind": False}])
|
||||
process_raw_issuance(self.nodes[0], [{"asset_amount": 7, "asset_address": nonblind_addr, "token_amount":2, "token_address":nonblind_addr, "blind":False}])
|
||||
process_raw_issuance(self.nodes[0], [{"asset_amount": 7, "asset_address": nonblind_addr, "token_amount":2, "token_address":blind_addr, "blind":False}])
|
||||
process_raw_issuance(self.nodes[0], [{"asset_amount": 7, "asset_address": blind_addr, "token_amount":2, "token_address":nonblind_addr, "blind":False}])
|
||||
process_raw_issuance(self.nodes[0], [{"asset_amount": 7, "asset_address": blind_addr, "token_amount":2, "token_address":blind_addr, "blind":False}])
|
||||
# Now do multiple with some issuance outputs blind, some unblinded
|
||||
process_raw_issuance(self.nodes[0], [{"asset_amount": 7, "asset_address": nonblind_addr, "token_amount":2, "token_address":nonblind_addr, "blind":False}, {"asset_amount":2, "asset_address":nonblind_addr, "blind":False}])
|
||||
process_raw_issuance(self.nodes[0], [{"asset_amount": 7, "asset_address": blind_addr, "token_amount":2, "token_address":nonblind_addr, "blind":False}, {"asset_amount":2, "asset_address":nonblind_addr, "blind":False}])
|
||||
# Up to 5 issuances since we're making 5 outputs each time
|
||||
process_raw_issuance(self.nodes[0], [{"asset_amount": 7, "asset_address": nonblind_addr, "token_amount":2, "token_address":blind_addr, "blind":False}, {"asset_amount":2, "asset_address":nonblind_addr, "blind":False}])
|
||||
process_raw_issuance(self.nodes[0], [{"asset_amount": 1, "asset_address": nonblind_addr, "token_amount":2, "token_address":blind_addr, "blind":False}, {"asset_amount":3, "asset_address":nonblind_addr, "blind":False}, {"asset_amount":4, "asset_address":nonblind_addr, "token_amount":5, "token_address":blind_addr, "blind":False}, {"asset_amount":6, "asset_address":nonblind_addr, "token_amount":7, "token_address":blind_addr, "blind":False}, {"asset_amount":8, "asset_address":nonblind_addr, "token_amount":9, "token_address":blind_addr, "blind":False}])
|
||||
# Default "blind" value is true, ommitting explicit argument for last
|
||||
process_raw_issuance(self.nodes[0], [{"asset_amount": 1, "asset_address": nonblind_addr, "token_amount":2, "token_address":blind_addr, "blind":True}, {"asset_amount":3, "asset_address":nonblind_addr, "blind":True}, {"asset_amount":4, "asset_address":nonblind_addr, "token_amount":5, "token_address":blind_addr, "blind":True}, {"asset_amount":6, "asset_address":nonblind_addr, "token_amount":7, "token_address":blind_addr, "blind":True}, {"asset_amount":8, "asset_address":nonblind_addr, "token_amount":9, "token_address":blind_addr}])
|
||||
|
||||
# Make sure contract hash is being interpreted as expected, resulting in different asset ids
|
||||
raw_tx = self.nodes[0].createrawtransaction([], {nonblind_addr:self.nodes[0].getbalance()['bitcoin']-1})
|
||||
funded_tx = self.nodes[0].fundrawtransaction(raw_tx)['hex']
|
||||
id_set = set()
|
||||
|
||||
# First issue an asset with no argument
|
||||
issued_tx = self.nodes[2].rawissueasset(funded_tx, [{"asset_amount":1, "asset_address":nonblind_addr}])[0]["hex"]
|
||||
decode_tx = self.nodes[0].decoderawtransaction(issued_tx)
|
||||
id_set.add(decode_tx["vin"][0]["issuance"]["asset"])
|
||||
|
||||
# Again with 00..00 argument, which match the no-argument case
|
||||
issued_tx = self.nodes[2].rawissueasset(funded_tx, [{"asset_amount":1, "asset_address":nonblind_addr, "contract_hash":"00"*32}])[0]["hex"]
|
||||
decode_tx = self.nodes[0].decoderawtransaction(issued_tx)
|
||||
id_set.add(decode_tx["vin"][0]["issuance"]["asset"])
|
||||
assert_equal(len(id_set), 1)
|
||||
|
||||
# Random contract string should again differ
|
||||
issued_tx = self.nodes[2].rawissueasset(funded_tx, [{"asset_amount":1, "asset_address":nonblind_addr, "contract_hash":"deadbeef"*8}])[0]["hex"]
|
||||
decode_tx = self.nodes[0].decoderawtransaction(issued_tx)
|
||||
id_set.add(decode_tx["vin"][0]["issuance"]["asset"])
|
||||
assert_equal(len(id_set), 2)
|
||||
issued_tx = self.nodes[2].rawissueasset(funded_tx, [{"asset_amount":1, "asset_address":nonblind_addr, "contract_hash":"deadbeee"*8}])[0]["hex"]
|
||||
decode_tx = self.nodes[0].decoderawtransaction(issued_tx)
|
||||
id_set.add(decode_tx["vin"][0]["issuance"]["asset"])
|
||||
assert_equal(len(id_set), 3)
|
||||
|
||||
# Finally, append an issuance on top of an already-"issued" raw tx
|
||||
# Same contract, different utxo being spent results in new asset type
|
||||
# We also create a reissuance token to test reissuance with contract hash
|
||||
issued_tx = self.nodes[2].rawissueasset(issued_tx, [{"asset_amount":1, "asset_address":nonblind_addr, "token_address":nonblind_addr, "contract":"deadbeee"*8}])[0]["hex"]
|
||||
decode_tx = self.nodes[0].decoderawtransaction(issued_tx)
|
||||
id_set.add(decode_tx["vin"][1]["issuance"]["asset"])
|
||||
assert_equal(len(id_set), 4)
|
||||
# This issuance should not have changed
|
||||
id_set.add(decode_tx["vin"][0]["issuance"]["asset"])
|
||||
assert_equal(len(id_set), 4)
|
||||
|
||||
print("Raw reissuance tests")
|
||||
issued_asset = self.nodes[0].issueasset(0, 1)
|
||||
self.nodes[0].generate(1)
|
||||
utxo_info = None
|
||||
# Find info about the token output using wallet
|
||||
for utxo in self.nodes[0].listunspent():
|
||||
if utxo["asset"] == issued_asset["token"]:
|
||||
utxo_info = utxo
|
||||
break
|
||||
assert(utxo_info is not None)
|
||||
|
||||
issued_address = self.nodes[0].getnewaddress()
|
||||
# Create transaction spending the reissuance token
|
||||
raw_tx = self.nodes[0].createrawtransaction([], {issued_address:Decimal('0.00000001')}, 0, False, {issued_address:issued_asset["token"]})
|
||||
funded_tx = self.nodes[0].fundrawtransaction(raw_tx)['hex']
|
||||
# Find the reissuance input
|
||||
reissuance_index = -1
|
||||
for i, tx_input in enumerate(self.nodes[0].decoderawtransaction(funded_tx)["vin"]):
|
||||
if tx_input["txid"] == utxo_info["txid"] and tx_input["vout"] == utxo_info["vout"]:
|
||||
reissuance_index = i
|
||||
break
|
||||
assert(reissuance_index != -1)
|
||||
reissued_tx = self.nodes[0].rawreissueasset(funded_tx, [{"asset_amount":3, "asset_address":self.nodes[0].getnewaddress(), "input_index":reissuance_index, "asset_blinder":utxo_info["assetblinder"], "entropy":issued_asset["entropy"]}])
|
||||
blind_tx = self.nodes[0].blindrawtransaction(reissued_tx["hex"])
|
||||
signed_tx = self.nodes[0].signrawtransactionwithwallet(blind_tx)
|
||||
tx_id = self.nodes[0].sendrawtransaction(signed_tx["hex"])
|
||||
self.nodes[0].generate(1)
|
||||
assert_equal(self.nodes[0].gettransaction(tx_id)["confirmations"], 1)
|
||||
|
||||
# Now send reissuance token to blinded multisig, then reissue
|
||||
addrs = []
|
||||
for i in range(3):
|
||||
addrs.append(self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())["pubkey"])
|
||||
|
||||
|
||||
multisig_addr = self.nodes[0].addmultisigaddress(2,addrs)
|
||||
blinded_addr = self.nodes[0].getnewaddress()
|
||||
blinding_pubkey = self.nodes[0].validateaddress(blinded_addr)["confidential_key"]
|
||||
blinding_privkey = self.nodes[0].dumpblindingkey(blinded_addr)
|
||||
blinded_multisig = self.nodes[0].createblindedaddress(multisig_addr["address"], blinding_pubkey)
|
||||
# Import blinding key to be able to decrypt values sent to it
|
||||
self.nodes[0].importblindingkey(blinded_multisig, blinding_privkey)
|
||||
# Sending to this address must achieve blinding to reissue from this address
|
||||
self.nodes[0].sendtoaddress(blinded_multisig, self.nodes[0].getbalance()[issued_asset["token"]], "", "", False, False, 1, "UNSET", issued_asset["token"], False)
|
||||
self.nodes[0].generate(1)
|
||||
|
||||
# Get that multisig output
|
||||
utxo_info = None
|
||||
# Find info about the token output using wallet
|
||||
for utxo in self.nodes[0].listunspent():
|
||||
if utxo["asset"] == issued_asset["token"]:
|
||||
utxo_info = utxo
|
||||
assert_equal(blinded_multisig, self.nodes[0].getaddressinfo(utxo_info["address"])["confidential"])
|
||||
break
|
||||
assert(utxo_info is not None)
|
||||
assert(utxo_info["amountblinder"] is not "0000000000000000000000000000000000000000000000000000000000000000")
|
||||
|
||||
# Now make transaction spending that input
|
||||
raw_tx = self.nodes[0].createrawtransaction([], {issued_address:1}, 0, False, {issued_address:issued_asset["token"]})
|
||||
funded_tx = self.nodes[0].fundrawtransaction(raw_tx)["hex"]
|
||||
# Find the reissuance input
|
||||
reissuance_index = -1
|
||||
for i, tx_input in enumerate(self.nodes[0].decoderawtransaction(funded_tx)["vin"]):
|
||||
if tx_input["txid"] == utxo_info["txid"] and tx_input["vout"] == utxo_info["vout"]:
|
||||
reissuance_index = i
|
||||
break
|
||||
assert(reissuance_index != -1)
|
||||
reissued_tx = self.nodes[0].rawreissueasset(funded_tx, [{"asset_amount":3, "asset_address":self.nodes[0].getnewaddress(), "input_index":reissuance_index, "asset_blinder":utxo_info["assetblinder"], "entropy":issued_asset["entropy"]}])
|
||||
|
||||
blind_tx = self.nodes[0].blindrawtransaction(reissued_tx["hex"])
|
||||
signed_tx = self.nodes[0].signrawtransactionwithwallet(blind_tx)
|
||||
tx_id = self.nodes[0].sendrawtransaction(signed_tx["hex"])
|
||||
self.nodes[0].generate(1)
|
||||
assert_equal(self.nodes[0].gettransaction(tx_id)["confirmations"], 1)
|
||||
|
||||
# Now make transaction spending a token that had non-null contract_hash
|
||||
contract_hash = "deadbeee"*8
|
||||
raw_tx = self.nodes[0].createrawtransaction([], {self.nodes[0].getnewaddress():1})
|
||||
funded_tx = self.nodes[0].fundrawtransaction(raw_tx)["hex"]
|
||||
issued_tx = self.nodes[0].rawissueasset(funded_tx, [{"token_amount":1, "token_address":self.nodes[0].getnewaddress(), "contract_hash":contract_hash}])[0]
|
||||
blinded_tx = self.nodes[0].blindrawtransaction(issued_tx["hex"])
|
||||
signed_tx = self.nodes[0].signrawtransactionwithwallet(blinded_tx)
|
||||
tx_id = self.nodes[0].sendrawtransaction(signed_tx["hex"])
|
||||
self.nodes[0].generate(1)
|
||||
assert_equal(self.nodes[0].gettransaction(tx_id)["confirmations"], 1)
|
||||
|
||||
utxo_info = None
|
||||
# Find info about the token output using wallet
|
||||
for utxo in self.nodes[0].listunspent():
|
||||
if utxo["asset"] == issued_tx["token"]:
|
||||
utxo_info = utxo
|
||||
break
|
||||
assert(utxo_info is not None)
|
||||
|
||||
# Now spend the token, and create reissuance
|
||||
raw_tx = self.nodes[0].createrawtransaction([], {issued_address:1}, 0, False, {issued_address:issued_tx["token"]})
|
||||
funded_tx = self.nodes[0].fundrawtransaction(raw_tx)["hex"]
|
||||
# Find the reissuance input
|
||||
reissuance_index = -1
|
||||
for i, tx_input in enumerate(self.nodes[0].decoderawtransaction(funded_tx)["vin"]):
|
||||
if tx_input["txid"] == utxo_info["txid"] and tx_input["vout"] == utxo_info["vout"]:
|
||||
reissuance_index = i
|
||||
break
|
||||
assert(reissuance_index != -1)
|
||||
reissued_tx = self.nodes[0].rawreissueasset(funded_tx, [{"asset_amount":3, "asset_address":self.nodes[0].getnewaddress(), "input_index":reissuance_index, "asset_blinder":utxo_info["assetblinder"], "entropy":issued_tx["entropy"]}])
|
||||
|
||||
blind_tx = self.nodes[0].blindrawtransaction(reissued_tx["hex"], False)
|
||||
signed_tx = self.nodes[0].signrawtransactionwithwallet(blind_tx)
|
||||
tx_id = self.nodes[0].sendrawtransaction(signed_tx["hex"])
|
||||
self.nodes[0].generate(1)
|
||||
assert_equal(self.nodes[0].gettransaction(tx_id)["confirmations"], 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
IssuanceTest ().main ()
|
||||
Loading…
Add table
Add a link
Reference in a new issue