Skip to content

Commit 292f9f5

Browse files
committed
Merge #867: [0.18 backport] Make issuance fail for invalid addresses
8e5893e Add test to make sure issuances to wrong addresses fail (Steven Roose) 21b3913 Make issuance fail for invalid addresses (Steven Roose) Pull request description: Backport of #861. Tree-SHA512: 6ef9d50c1b63d93dd3497b38510e8628d02dd876d85b270e3ede4c68118aaf1e7cd3c73ee7f35d7b51cc7500517f3cedd4e0bf5d4de0be373a51ae008d89cf15
2 parents 5e0057a + 8e5893e commit 292f9f5

File tree

2 files changed

+57
-37
lines changed

2 files changed

+57
-37
lines changed

src/rpc/rawtransaction.cpp

+43-37
Original file line numberDiff line numberDiff line change
@@ -2584,13 +2584,10 @@ struct RawIssuanceDetails
25842584

25852585
// Appends a single issuance to the first input that doesn't have one, and includes
25862586
// a single output per asset type in shuffled positions.
2587-
void issueasset_base(CMutableTransaction& mtx, RawIssuanceDetails& issuance_details, const CAmount asset_amount, const CAmount token_amount, const std::string& asset_address_str, const std::string& token_address_str, const bool blind_issuance, const uint256& contract_hash)
2587+
void issueasset_base(CMutableTransaction& mtx, RawIssuanceDetails& issuance_details, const CAmount asset_amount, const CAmount token_amount, const CTxDestination& asset_dest, const CTxDestination& token_dest, const bool blind_issuance, const uint256& contract_hash)
25882588
{
2589-
2590-
CTxDestination asset_address(DecodeDestination(asset_address_str));
2591-
CTxDestination token_address(DecodeDestination(token_address_str));
2592-
CScript asset_destination = GetScriptForDestination(asset_address);
2593-
CScript token_destination = GetScriptForDestination(token_address);
2589+
CScript asset_script = GetScriptForDestination(asset_dest);
2590+
CScript token_script = GetScriptForDestination(token_dest);
25942591

25952592
// Find an input with no issuance field
25962593
size_t issuance_input_index = 0;
@@ -2624,41 +2621,40 @@ void issueasset_base(CMutableTransaction& mtx, RawIssuanceDetails& issuance_deta
26242621
int asset_place = GetRandInt(mtx.vout.size()-1);
26252622
int token_place = GetRandInt(mtx.vout.size()); // Don't bias insertion
26262623

2627-
CTxOut asset_out(asset, asset_amount, asset_destination);
2628-
// If blinded address, insert the pubkey into the nonce field for later substitution by blinding
2629-
if (IsBlindDestination(asset_address)) {
2630-
CPubKey asset_blind = GetDestinationBlindingKey(asset_address);
2631-
asset_out.nNonce.vchCommitment = std::vector<unsigned char>(asset_blind.begin(), asset_blind.end());
2624+
assert(asset_amount > 0 || token_amount > 0);
2625+
if (asset_amount > 0) {
2626+
CTxOut asset_out(asset, asset_amount, asset_script);
2627+
// If blinded address, insert the pubkey into the nonce field for later substitution by blinding
2628+
if (IsBlindDestination(asset_dest)) {
2629+
CPubKey asset_blind = GetDestinationBlindingKey(asset_dest);
2630+
asset_out.nNonce.vchCommitment = std::vector<unsigned char>(asset_blind.begin(), asset_blind.end());
2631+
}
2632+
2633+
mtx.vout.insert(mtx.vout.begin()+asset_place, asset_out);
26322634
}
26332635
// Explicit 0 is represented by a null value, don't set to non-null in that case
26342636
if (blind_issuance || asset_amount != 0) {
26352637
mtx.vin[issuance_input_index].assetIssuance.nAmount = asset_amount;
26362638
}
2637-
// Don't make zero value output(impossible by consensus)
2638-
if (asset_amount > 0) {
2639-
mtx.vout.insert(mtx.vout.begin()+asset_place, asset_out);
2640-
}
26412639

2642-
CTxOut token_out(token, token_amount, token_destination);
2643-
// If blinded address, insert the pubkey into the nonce field for later substitution by blinding
2644-
if (IsBlindDestination(token_address)) {
2645-
CPubKey token_blind = GetDestinationBlindingKey(token_address);
2646-
token_out.nNonce.vchCommitment = std::vector<unsigned char>(token_blind.begin(), token_blind.end());
2647-
}
2648-
// Explicit 0 is represented by a null value, don't set to non-null in that case
26492640
if (token_amount > 0) {
2641+
CTxOut token_out(token, token_amount, token_script);
2642+
// If blinded address, insert the pubkey into the nonce field for later substitution by blinding
2643+
if (IsBlindDestination(token_dest)) {
2644+
CPubKey token_blind = GetDestinationBlindingKey(token_dest);
2645+
token_out.nNonce.vchCommitment = std::vector<unsigned char>(token_blind.begin(), token_blind.end());
2646+
}
2647+
26502648
mtx.vin[issuance_input_index].assetIssuance.nInflationKeys = token_amount;
26512649
mtx.vout.insert(mtx.vout.begin()+token_place, token_out);
26522650
}
26532651
}
26542652

26552653
// Appends a single reissuance to the specified input if none exists,
26562654
// and the corresponding output in a shuffled position. Errors otherwise.
2657-
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)
2655+
void reissueasset_base(CMutableTransaction& mtx, int& issuance_input_index, const CAmount asset_amount, const CTxDestination& asset_dest, const uint256& asset_blinder, const uint256& entropy)
26582656
{
2659-
2660-
CTxDestination asset_address(DecodeDestination(asset_address_str));
2661-
CScript asset_destination = GetScriptForDestination(asset_address);
2657+
CScript asset_script = GetScriptForDestination(asset_dest);
26622658

26632659
// Check if issuance already exists, error if already exists
26642660
if ((size_t)issuance_input_index >= mtx.vin.size() || !mtx.vin[issuance_input_index].assetIssuance.IsNull()) {
@@ -2677,10 +2673,10 @@ void reissueasset_base(CMutableTransaction& mtx, int& issuance_input_index, cons
26772673
assert(mtx.vout.size() >= 1);
26782674
int asset_place = GetRandInt(mtx.vout.size()-1);
26792675

2680-
CTxOut asset_out(asset, asset_amount, asset_destination);
2676+
CTxOut asset_out(asset, asset_amount, asset_script);
26812677
// If blinded address, insert the pubkey into the nonce field for later substitution by blinding
2682-
if (IsBlindDestination(asset_address)) {
2683-
CPubKey asset_blind = GetDestinationBlindingKey(asset_address);
2678+
if (IsBlindDestination(asset_dest)) {
2679+
CPubKey asset_blind = GetDestinationBlindingKey(asset_dest);
26842680
asset_out.nNonce.vchCommitment = std::vector<unsigned char>(asset_blind.begin(), asset_blind.end());
26852681
}
26862682
assert(asset_amount > 0);
@@ -2733,9 +2729,6 @@ UniValue rawissueasset(const JSONRPCRequest& request)
27332729

27342730
UniValue issuances = request.params[1].get_array();
27352731

2736-
std::string asset_address_str = "";
2737-
std::string token_address_str = "";
2738-
27392732
UniValue ret(UniValue::VARR);
27402733

27412734
// Count issuances, only append hex to final one
@@ -2745,6 +2738,9 @@ UniValue rawissueasset(const JSONRPCRequest& request)
27452738
const UniValue& issuance = issuances[idx];
27462739
const UniValue& issuance_o = issuance.get_obj();
27472740

2741+
CTxDestination asset_dest = CNoDestination();
2742+
CTxDestination token_dest = CNoDestination();
2743+
27482744
CAmount asset_amount = 0;
27492745
const UniValue& asset_amount_uni = issuance_o["asset_amount"];
27502746
if (asset_amount_uni.isNum()) {
@@ -2756,7 +2752,10 @@ UniValue rawissueasset(const JSONRPCRequest& request)
27562752
if (!asset_address_uni.isStr()) {
27572753
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing corresponding asset_address");
27582754
}
2759-
asset_address_str = asset_address_uni.get_str();
2755+
asset_dest = DecodeDestination(asset_address_uni.get_str());
2756+
if (boost::get<CNoDestination>(&asset_dest)) {
2757+
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid asset address provided: %s", asset_address_uni.get_str()));
2758+
}
27602759
}
27612760

27622761
CAmount token_amount = 0;
@@ -2770,8 +2769,12 @@ UniValue rawissueasset(const JSONRPCRequest& request)
27702769
if (!token_address_uni.isStr()) {
27712770
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing corresponding token_address");
27722771
}
2773-
token_address_str = token_address_uni.get_str();
2772+
token_dest = DecodeDestination(token_address_uni.get_str());
2773+
if (boost::get<CNoDestination>(&token_dest)) {
2774+
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid token address provided: %s", token_address_uni.get_str()));
2775+
}
27742776
}
2777+
27752778
if (asset_amount == 0 && token_amount == 0) {
27762779
throw JSONRPCError(RPC_TYPE_ERROR, "Issuance must have one non-zero component");
27772780
}
@@ -2788,7 +2791,7 @@ UniValue rawissueasset(const JSONRPCRequest& request)
27882791

27892792
RawIssuanceDetails details;
27902793

2791-
issueasset_base(mtx, details, asset_amount, token_amount, asset_address_str, token_address_str, blind_issuance, contract_hash);
2794+
issueasset_base(mtx, details, asset_amount, token_amount, asset_dest, token_dest, blind_issuance, contract_hash);
27922795
if (details.input_index == -1) {
27932796
throw JSONRPCError(RPC_INVALID_PARAMETER, "Failed to find enough blank inputs for listed issuances.");
27942797
}
@@ -2872,7 +2875,10 @@ UniValue rawreissueasset(const JSONRPCRequest& request)
28722875
if (!asset_address_uni.isStr()) {
28732876
throw JSONRPCError(RPC_INVALID_PARAMETER, "Reissuance missing asset_address");
28742877
}
2875-
std::string asset_address_str = asset_address_uni.get_str();
2878+
CTxDestination asset_dest = DecodeDestination(asset_address_uni.get_str());
2879+
if (boost::get<CNoDestination>(&asset_dest)) {
2880+
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid asset address provided: %s", asset_address_uni.get_str()));
2881+
}
28762882

28772883
int input_index = -1;
28782884
const UniValue& input_index_o = issuance_o["input_index"];
@@ -2889,7 +2895,7 @@ UniValue rawreissueasset(const JSONRPCRequest& request)
28892895

28902896
uint256 entropy = ParseHashV(issuance_o["entropy"], "entropy");
28912897

2892-
reissueasset_base(mtx, input_index, asset_amount, asset_address_str, asset_blinder, entropy);
2898+
reissueasset_base(mtx, input_index, asset_amount, asset_dest, asset_blinder, entropy);
28932899
if (input_index == -1) {
28942900
throw JSONRPCError(RPC_INVALID_PARAMETER, "Selected transaction input already has issuance data.");
28952901
}

test/functional/feature_issuance.py

+14
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,20 @@ def run_test(self):
290290
# Default "blind" value is true, omitting explicit argument for last
291291
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}])
292292

293+
# Make sure that invalid addresses are rejected.
294+
valid_addr = self.nodes[0].getnewaddress()
295+
raw_tx = self.nodes[0].createrawtransaction([], {valid_addr: Decimal("1")})
296+
funded_tx = raw_tx #self.nodes[0].fundrawtransaction(raw_tx, {"feeRate": Decimal('0.00050000')})['hex']
297+
assert_raises_rpc_error(-8, "Invalid asset address provided: foobar",
298+
self.nodes[0].rawissueasset, funded_tx, [{"asset_amount": 1, "asset_address": "foobar"}])
299+
assert_raises_rpc_error(-8, "Invalid token address provided: foobar",
300+
self.nodes[0].rawissueasset, funded_tx, [{"token_amount": 1, "token_address": "foobar"}])
301+
# Also test for missing value.
302+
assert_raises_rpc_error(-8, "Invalid parameter, missing corresponding asset_address",
303+
self.nodes[0].rawissueasset, funded_tx, [{"asset_amount": 1, "token_address": valid_addr}])
304+
assert_raises_rpc_error(-8, "Invalid parameter, missing corresponding token_address",
305+
self.nodes[0].rawissueasset, funded_tx, [{"token_amount": 1, "asset_address": valid_addr}])
306+
293307
# Make sure contract hash is being interpreted as expected, resulting in different asset ids
294308
raw_tx = self.nodes[0].createrawtransaction([], {nonblind_addr:self.nodes[0].getbalance()['bitcoin']-1})
295309
funded_tx = self.nodes[0].fundrawtransaction(raw_tx)['hex']

0 commit comments

Comments
 (0)