From 756bdc060ef6dfa4ce61fde4601033d84aa2dd9d Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Wed, 12 Dec 2018 16:13:55 -0500 Subject: [PATCH 1/8] issueasset_base: Push 0-value value to issuance field if blinding --- src/rpc/rawtransaction.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index bf21a1f421e..55cdfc4421e 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1635,10 +1635,13 @@ void issueasset_base(CMutableTransaction& mtx, IssuanceDetails& issuance_details CPubKey asset_blind = asset_address.GetBlindingKey(); asset_out.nNonce.vchCommitment = std::vector(asset_blind.begin(), asset_blind.end()); } - // Don't issue stuff or set values unless non-zero (both are against consensus) + // Explicit 0 is represented by a null value, don't set to non-null in that case + if (blind_issuance || asset_amount != 0) { + mtx.vin[issuance_input_index].assetIssuance.nAmount = asset_amount; + } + // Don't make zero value output(impossible by consensus) if (asset_amount > 0) { mtx.vout.insert(mtx.vout.begin()+asset_place, asset_out); - mtx.vin[issuance_input_index].assetIssuance.nAmount = asset_amount; } CTxOut token_out(token, token_amount, token_destination); @@ -1647,10 +1650,13 @@ void issueasset_base(CMutableTransaction& mtx, IssuanceDetails& issuance_details CPubKey token_blind = token_address.GetBlindingKey(); token_out.nNonce.vchCommitment = std::vector(token_blind.begin(), token_blind.end()); } - // Don't issue stuff or set values unless non-zero (both are against consensus) + // Explicit 0 is represented by a null value, don't set to non-null in that case + if (blind_issuance || token_amount != 0) { + mtx.vin[issuance_input_index].assetIssuance.nInflationKeys = token_amount; + } + // Don't make zero value output(impossible by consensus) if (token_amount > 0) { mtx.vout.insert(mtx.vout.begin()+token_place, token_out); - mtx.vin[issuance_input_index].assetIssuance.nInflationKeys = token_amount; } } From fff2dccc1e6e33a3efd0b399f5859e9fa7439adf Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Wed, 12 Dec 2018 16:11:49 -0500 Subject: [PATCH 2/8] blindrawtransaction: Have blind_issuances parse correctly from command line --- src/rpc/client.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index bf3b04efbec..8c56f9a0a26 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -93,6 +93,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "rawblindrawtransaction", 6, "ignoreblindfail" }, { "blindrawtransaction", 1, "assetcommitments" }, { "blindrawtransaction", 2, "ignoreblindfail" }, + { "blindrawtransaction", 3, "blind_issuances" }, { "createrawtransaction", 0, "inputs" }, { "createrawtransaction", 1, "outputs" }, { "dumpissuanceblindingkey", 1, "vin" }, From c579f4b52405cd2ed60b49110193b2d4730b95a4 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Wed, 12 Dec 2018 16:12:30 -0500 Subject: [PATCH 3/8] Correct how wallet blinding logic detects which token id to use based on blinding keys --- src/blind.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/blind.cpp b/src/blind.cpp index ebc9cd2ed6a..ac4e5ff8865 100644 --- a/src/blind.cpp +++ b/src/blind.cpp @@ -265,10 +265,10 @@ int BlindTransaction(std::vector& input_blinding_factors, const std::v } // New Issuance if (issuance.assetBlindingNonce.IsNull()) { - bool assetToBlind = (vBlindIssuanceAsset.size() > i && vBlindIssuanceAsset[i].IsValid()) ? true : false; + bool blind_issuance = (vBlindIssuanceToken.size() > i && vBlindIssuanceToken[i].IsValid()) ? true : false; GenerateAssetEntropy(entropy, tx.vin[i].prevout, issuance.assetEntropy); CalculateAsset(asset, entropy); - CalculateReissuanceToken(token, entropy, assetToBlind); + CalculateReissuanceToken(token, entropy, blind_issuance); } else { CalculateAsset(asset, issuance.assetEntropy); } @@ -395,8 +395,8 @@ int BlindTransaction(std::vector& input_blinding_factors, const std::v if (nPseudo == 0) { CalculateAsset(asset, entropy); } else { - bool assetToBlind = (vBlindIssuanceAsset.size() > nIn && vBlindIssuanceAsset[nIn].IsValid()) ? true : false; - CalculateReissuanceToken(asset, entropy, assetToBlind); + bool blind_issuance = (vBlindIssuanceToken.size() > nIn && vBlindIssuanceToken[nIn].IsValid()) ? true : false; + CalculateReissuanceToken(asset, entropy, blind_issuance); } } else { if (nPseudo == 0) { From 23371af2626045da0ac7400169a3eb5bc9220ca3 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Mon, 3 Dec 2018 16:49:33 +0100 Subject: [PATCH 4/8] add confidential_key explanation in validateaddress help --- src/rpc/misc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index cb472a298a2..3a2b1c2f80e 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -184,6 +184,7 @@ UniValue validateaddress(const JSONRPCRequest& request) " \"timestamp\" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT)\n" " \"unconfidential\" : \"address\" (string) The address without confidentiality key\n" " \"confidential\" : \"address\" (string) Confidential version of the address, only if it is yours and unconfidential\n" + " \"confidential_key\" : \"publickeyhex\" (string) The hex value of the raw blinding public key for that address, if any.\n" " \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n" " \"hdmasterkeyid\" : \"\" (string, optional) The Hash160 of the HD master pubkey\n" "}\n" From 1251ecd411da5b2b7d68157ae1ba21d46e3d444b Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Wed, 12 Dec 2018 16:27:16 -0500 Subject: [PATCH 5/8] fixup rawissueasset help comment --- src/rpc/rawtransaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 55cdfc4421e..95f1e931126 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1667,7 +1667,7 @@ UniValue rawissueasset(const JSONRPCRequest& request) "rawissueasset transaction [{\"asset_amount\":x.xxx, \"asset_address\":\"address\", \"token_amount\":x.xxx, \"token_address\":\"address\", \"blind\":bool, ( \"contract_hash\":\"hash\" )}, ...]\n" "\nCreate an asset by attaching issuances to transaction inputs. Returns the transaction hex. There must be as many inputs as issuances requested. The final transaction hex is the final version of the transaction appended to the last object in the array.\n" "\nArguments:\n" - "1. \"transaction\" (string, required) Transaction in hex in which to include a peg-in input.\n" + "1. \"transaction\" (string, required) Transaction in hex in which to include an issuance input.\n" "2. \"issuances\" (list, required) List of issuances to create. Each issuance must have one non-zero amount. \n" "[\n" " {\n" From 21cb8aab9b5f1fe4d3f1e2a3bc9505a369d44b56 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Sat, 1 Dec 2018 16:02:40 -0500 Subject: [PATCH 6/8] rawreissuance rpc --- src/rpc/client.cpp | 1 + src/rpc/rawtransaction.cpp | 127 +++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 8c56f9a0a26..8f139878ed0 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -143,6 +143,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "sendtomainchain", 2, "subtractfeefromamount"}, { "getnewblockhex", 0, "required_age"}, { "rawissueasset", 1, "issuances"}, + { "rawreissueasset", 1, "reissuances"}, // Echo with conversion (For testing only) { "echojson", 0, "arg0" }, { "echojson", 1, "arg1" }, diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 95f1e931126..4c4b064648b 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1660,6 +1660,42 @@ void issueasset_base(CMutableTransaction& mtx, IssuanceDetails& issuance_details } } +// Appends a single reissuance to the specified input if none exists, +// and the corresponding output in a shuffled position. Errors otherwise. +void reissueasset_base(CMutableTransaction& mtx, int& issuance_input_index, const CAmount asset_amount, const std::string& asset_address_str, const uint256& asset_blinder, const uint256& entropy) +{ + + CBitcoinAddress asset_address(asset_address_str); + CScript asset_destination = GetScriptForDestination(asset_address.Get()); + + // Check if issuance already exists, error if already exists + if ((size_t)issuance_input_index >= mtx.vin.size() || !mtx.vin[issuance_input_index].assetIssuance.IsNull()) { + issuance_input_index = -1; + return; + } + + CAsset asset; + CalculateAsset(asset, entropy); + + mtx.vin[issuance_input_index].assetIssuance.assetEntropy = entropy; + mtx.vin[issuance_input_index].assetIssuance.assetBlindingNonce = asset_blinder; + mtx.vin[issuance_input_index].assetIssuance.nAmount = asset_amount; + + // Place assets into randomly placed output slots, before change output, inserted in place + assert(mtx.vout.size() >= 1); + int asset_place = GetRandInt(mtx.vout.size()-1); + + CTxOut asset_out(asset, asset_amount, asset_destination); + // If blinded address, insert the pubkey into the nonce field for later substitution by blinding + if (asset_address.IsBlinded()) { + CPubKey asset_blind = asset_address.GetBlindingKey(); + asset_out.nNonce.vchCommitment = std::vector(asset_blind.begin(), asset_blind.end()); + } + assert(asset_amount > 0); + mtx.vout.insert(mtx.vout.begin()+asset_place, asset_out); + mtx.vin[issuance_input_index].assetIssuance.nAmount = asset_amount; +} + UniValue rawissueasset(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 2) @@ -1777,6 +1813,96 @@ UniValue rawissueasset(const JSONRPCRequest& request) return ret; } +UniValue rawreissueasset(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 2) + throw runtime_error( + "rawreissueasset transaction {\"vin\":\"n\", \"asset_amount\":x.xxx, \"asset_address\":\"address\", \"asset_blinder\":, \"entropy\":, ( \"contract_hash\": )}\n" + "\nRe-issue an asset by attaching pseudo-inputs to transaction inputs, revealing the underlying reissuance token of the input. Returns the transaction hex.\n" + "\nArguments:\n" + "1. \"transaction\" (string, required) Transaction in hex in which to include an issuance input.\n" + "2. \"reissuances\" (list, required) List of re-issuances to create. Each issuance must have one non-zero amount.\n" + "[\n" + " {\n" + " \"input_index\":\"n\", (numeric, required) The input position of the reissuance in the transaction.\n" + " \"asset_amount\":x.xxx, (numeric or string, required) Amount of asset to generate, if any.\n" + " \"asset_address\":addr, (string, required) Destination address of generated asset. Required if `asset_amount` given.\n" + " \"asset_blinder\":, (string, required) The blinding factor of the reissuance token output being spent.\n" + " \"entropy\":, (string, required) The `entropy` returned during initial issuance for the asset being reissued." + " }\n" + "\nResult:\n" + "{ (json object)\n" + " \"hex\":, (string) The transaction with reissuances appended.\n" + "}\n" + ); + + CMutableTransaction mtx; + + if (!DecodeHexTx(mtx, request.params[0].get_str())) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + + if (mtx.vout.empty()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction must have at least one output."); + } + + UniValue issuances = request.params[1].get_array(); + + unsigned int num_issuances = 0; + + for (unsigned int idx = 0; idx < issuances.size(); idx++) { + const UniValue& issuance = issuances[idx]; + const UniValue& issuance_o = issuance.get_obj(); + + CAmount asset_amount = 0; + const UniValue& asset_amount_uni = issuance_o["asset_amount"]; + if (asset_amount_uni.isNum()) { + asset_amount = AmountFromValue(asset_amount_uni); + if (asset_amount <= 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, asset_amount must be positive"); + } + } else { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Asset amount must be given for each reissuance."); + } + + const UniValue& asset_address_uni = issuance_o["asset_address"]; + if (!asset_address_uni.isStr()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Reissuance missing asset_address"); + } + std::string asset_address_str = asset_address_uni.get_str(); + + int input_index = -1; + const UniValue& input_index_o = issuance_o["input_index"]; + if (input_index_o.isNum()) { + input_index = input_index_o.get_int(); + if (input_index < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Input index must be non-negative."); + } + } else { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Input indexes for all reissuances are required."); + } + + uint256 asset_blinder = ParseHashV(issuance_o["asset_blinder"], "asset_blinder"); + + uint256 entropy = ParseHashV(issuance_o["entropy"], "entropy"); + + reissueasset_base(mtx, input_index, asset_amount, asset_address_str, asset_blinder, entropy); + if (input_index == -1) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Selected transaction input already has issuance data."); + } + + num_issuances++; + } + + if (num_issuances != issuances.size()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Failed to find enough blank inputs for listed issuances."); + } + + UniValue ret(UniValue::VOBJ); + ret.pushKV("hex", EncodeHexTx(mtx, RPCSerializationFlags())); + return ret; +} + + static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- @@ -1788,6 +1914,7 @@ static const CRPCCommand commands[] = { "rawtransactions", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */ { "rawtransactions", "rawblindrawtransaction", &rawblindrawtransaction, false, {}}, { "rawtransactions", "rawissueasset", &rawissueasset, false, {"transaction", "issuances"}}, + { "rawtransactions", "rawreissueasset", &rawreissueasset, false, {"transaction", "reissuances"}}, #ifdef ENABLE_WALLET { "rawtransactions", "blindrawtransaction", &blindrawtransaction, true, {"hexstring", "ignoreblindfail", "asset_commitments", "blind_issuances", "totalblinder"}}, #endif From 181d09958bc7b061198f9a1e96a5af0d7c49f2b8 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Sun, 2 Dec 2018 17:18:05 +0100 Subject: [PATCH 7/8] rawreissueasset functional tests --- qa/rpc-tests/feature_issuance.py | 120 ++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 3 deletions(-) diff --git a/qa/rpc-tests/feature_issuance.py b/qa/rpc-tests/feature_issuance.py index ea3284cfac3..57d4836d519 100755 --- a/qa/rpc-tests/feature_issuance.py +++ b/qa/rpc-tests/feature_issuance.py @@ -248,8 +248,8 @@ def run_test(self): self.nodes[1].generate(1) raw_tx = self.nodes[0].createrawtransaction([], {nonblind_addr:self.nodes[0].getbalance()['bitcoin']-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}])[0]["hex"] - blind_tx = self.nodes[0].blindrawtransaction(issued_tx) + 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].signrawtransaction(blind_tx) assert_raises_jsonrpc(-26, "", self.nodes[0].sendrawtransaction, signed_tx['hex']) @@ -303,13 +303,127 @@ def run_test(self): # Finally, append an issuance on top of an already-"issued" raw tx # Same contract, different utxo being spent results in new asset type - issued_tx = self.nodes[2].rawissueasset(issued_tx, [{"asset_amount":1, "asset_address":nonblind_addr, "contract":"deadbeee"*8}])[0]["hex"] + # 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"]) + non_null_contract_token = decode_tx["vin"][1]["issuance"]["token"] 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, {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].signrawtransaction(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].validateaddress(self.nodes[0].getnewaddress())["pubkey"]) + + + multisig_addr = self.nodes[0].createmultisig(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 address so we consider the reissuance tokens ours + self.nodes[0].importaddress(blinded_multisig) + # Import blinding key to be able to decrypt values sent to it + self.nodes[0].importblindingkey(blinded_multisig, blinding_privkey) + + self.nodes[0].sendtoaddress(blinded_multisig, self.nodes[0].getbalance()[issued_asset["asset"]], "", "", False, issued_asset["asset"]) + 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 + break + assert(utxo_info is not None) + + # Now make transaction spending that input + raw_tx = self.nodes[0].createrawtransaction([], {issued_address:1}, 0, {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].signrawtransaction(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].signrawtransaction(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, {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].signrawtransaction(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 () From bc257db852a96614252f281c46f77e26a43f353b Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Mon, 17 Dec 2018 15:52:59 -0500 Subject: [PATCH 8/8] f'rawreissueasset functional tests' --- qa/rpc-tests/feature_issuance.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qa/rpc-tests/feature_issuance.py b/qa/rpc-tests/feature_issuance.py index 57d4836d519..8c7aeaf8073 100755 --- a/qa/rpc-tests/feature_issuance.py +++ b/qa/rpc-tests/feature_issuance.py @@ -307,7 +307,6 @@ def run_test(self): 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"]) - non_null_contract_token = decode_tx["vin"][1]["issuance"]["token"] assert_equal(len(id_set), 4) # This issuance should not have changed id_set.add(decode_tx["vin"][0]["issuance"]["asset"])