Skip to content

Commit 2eb5b08

Browse files
tomt1664Tom Trevethandelta1
authored
Enable sending of different assets to the same address (#1479)
* enable rawtransaction send multiple assets to same address * fix whitespace * Update test/functional/feature_issuance.py Co-authored-by: Byron Hambly <[email protected]> * Update test/functional/feature_issuance.py Co-authored-by: Byron Hambly <[email protected]> --------- Co-authored-by: Tom Trevethan <[email protected]> Co-authored-by: Byron Hambly <[email protected]>
1 parent 3524ec0 commit 2eb5b08

File tree

3 files changed

+35
-7
lines changed

3 files changed

+35
-7
lines changed

src/rpc/rawtransaction_util.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
283283
CTxOut fee_out;
284284

285285
// Duplicate checking
286-
std::set<CTxDestination> destinations;
286+
std::set<std::pair<CTxDestination,CAsset>> destinations;
287287
bool has_data{false};
288288

289289
std::vector<PSBTOutput> psbt_outs;
@@ -297,6 +297,8 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
297297
CTxOut out(::policyAsset, 0, CScript());
298298

299299
bool is_fee = false;
300+
CTxDestination destination;
301+
std::string dest;
300302
for (const std::string& name_ : output.getKeys()) {
301303
if (name_ == "data") {
302304
if (has_data) {
@@ -337,14 +339,11 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
337339
// For PSET
338340
psbt_out.m_blinder_index = find_value(output, name_).get_int();
339341
} else {
340-
CTxDestination destination = DecodeDestination(name_);
342+
destination = DecodeDestination(name_);
341343
if (!IsValidDestination(destination)) {
342344
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
343345
}
344-
345-
if (!destinations.insert(destination).second) {
346-
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
347-
}
346+
dest = name_;
348347

349348
CScript scriptPubKey = GetScriptForDestination(destination);
350349
CAmount nAmount = AmountFromValue(output[name_]);
@@ -362,6 +361,11 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
362361
psbt_out.m_blinding_pubkey = blind_pub;
363362
}
364363
}
364+
365+
if (!destinations.emplace(destination, out.nAsset.GetAsset()).second) {
366+
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address and asset: " + dest + " " + out.nAsset.GetHex()));
367+
}
368+
365369
if (is_fee) {
366370
fee_out = out;
367371
} else {

test/functional/feature_issuance.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,5 +502,29 @@ def run_test(self):
502502
# an "impossible" case and a confusing/generic error message.
503503
self.nodes[1].issueasset(0, 1, False)["txid"]
504504

505+
# Send different assets to the same address in a transaction with createrawtransaction
506+
# Unblinded issuance of asset
507+
contract_hash_1 = "deadbee1"*8
508+
contract_hash_2 = "deadbee2"*8
509+
issued_1 = self.nodes[0].issueasset(1, 1, False, contract_hash_1)
510+
issued_2 = self.nodes[0].issueasset(1, 1, False, contract_hash_2)
511+
self.generate(self.nodes[0], 1)
512+
self.sync_all()
513+
balance = self.nodes[0].getwalletinfo()["balance"]
514+
assert_equal(balance[issued_1["asset"]], 1)
515+
assert_equal(balance[issued_2["asset"]], 1)
516+
517+
send_address = self.nodes[0].getnewaddress()
518+
519+
# error generated if duplicated address:asset pair
520+
assert_raises_rpc_error(-8, "Invalid parameter, duplicated address and asset", self.nodes[0].createrawtransaction, [], [{send_address: 1, "asset": issued_1["asset"]}, {send_address: 1, "asset": issued_1["asset"]}], 0, False)
521+
522+
# repeated address with different asset accepted
523+
raw_tx = self.nodes[0].createrawtransaction([], [{send_address: 1, "asset": issued_1["asset"]}, {send_address: 1, "asset": issued_2["asset"]}], 0, False)
524+
funded_tx = self.nodes[0].fundrawtransaction(raw_tx)["hex"]
525+
blind_tx = self.nodes[0].blindrawtransaction(funded_tx)
526+
signed_tx = self.nodes[0].signrawtransactionwithwallet(blind_tx)
527+
self.nodes[0].sendrawtransaction(signed_tx["hex"])
528+
505529
if __name__ == '__main__':
506530
IssuanceTest ().main ()

test/functional/rpc_rawtransaction.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ def createrawtransaction_tests(self):
221221
assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].createrawtransaction, [], [{'foo': 0}])
222222
assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].createrawtransaction, [], [{address: 'foo'}])
223223
assert_raises_rpc_error(-3, "Amount out of range", self.nodes[0].createrawtransaction, [], [{address: -1}])
224-
assert_raises_rpc_error(-8, "Invalid parameter, duplicated address: %s" % address, self.nodes[0].createrawtransaction, [], [{address: 1}, {address: 1}])
224+
assert_raises_rpc_error(-8, "Invalid parameter, duplicated address and asset: %s" % address, self.nodes[0].createrawtransaction, [], [{address: 1}, {address: 1}])
225225
assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data", self.nodes[0].createrawtransaction, [], [{"data": 'aa'}, {"data": "bb"}])
226226
assert_raises_rpc_error(-1, "JSON value is not an object as expected", self.nodes[0].createrawtransaction, [], [['key-value pair1'], ['2']])
227227

0 commit comments

Comments
 (0)