Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions src/rpc/rawtransaction_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
CTxOut fee_out;

// Duplicate checking
std::set<CTxDestination> destinations;
std::set<std::pair<CTxDestination,CAsset>> destinations;
bool has_data{false};

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

bool is_fee = false;
CTxDestination destination;
std::string dest;
for (const std::string& name_ : output.getKeys()) {
if (name_ == "data") {
if (has_data) {
Expand Down Expand Up @@ -337,14 +339,11 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
// For PSET
psbt_out.m_blinder_index = find_value(output, name_).get_int();
} else {
CTxDestination destination = DecodeDestination(name_);
destination = DecodeDestination(name_);
if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
}

if (!destinations.insert(destination).second) {
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
}
dest = name_;

CScript scriptPubKey = GetScriptForDestination(destination);
CAmount nAmount = AmountFromValue(output[name_]);
Expand All @@ -362,6 +361,11 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
psbt_out.m_blinding_pubkey = blind_pub;
}
}

if (!destinations.emplace(destination, out.nAsset.GetAsset()).second) {
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address and asset: " + dest + " " + out.nAsset.GetHex()));
}

if (is_fee) {
fee_out = out;
} else {
Expand Down
24 changes: 24 additions & 0 deletions test/functional/feature_issuance.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,5 +502,29 @@ def run_test(self):
# an "impossible" case and a confusing/generic error message.
self.nodes[1].issueasset(0, 1, False)["txid"]

# Send different assets to the same address in a transaction with createrawtransaction
# Unblinded issuance of asset
contract_hash_1 = "deadbee1"*8
contract_hash_2 = "deadbee2"*8
issued_1 = self.nodes[0].issueasset(1, 1, False, contract_hash_1)
issued_2 = self.nodes[0].issueasset(1, 1, False, contract_hash_2)
self.generate(self.nodes[0], 1)
self.sync_all()
balance = self.nodes[0].getwalletinfo()["balance"]
assert_equal(balance[issued_1["asset"]], 1)
assert_equal(balance[issued_2["asset"]], 1)

send_address = self.nodes[0].getnewaddress()

# error generated if duplicated address:asset pair
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)

# repeated address with different asset accepted
raw_tx = self.nodes[0].createrawtransaction([], [{send_address: 1, "asset": issued_1["asset"]}, {send_address: 1, "asset": issued_2["asset"]}], 0, False)
funded_tx = self.nodes[0].fundrawtransaction(raw_tx)["hex"]
blind_tx = self.nodes[0].blindrawtransaction(funded_tx)
signed_tx = self.nodes[0].signrawtransactionwithwallet(blind_tx)
self.nodes[0].sendrawtransaction(signed_tx["hex"])

if __name__ == '__main__':
IssuanceTest ().main ()
2 changes: 1 addition & 1 deletion test/functional/rpc_rawtransaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ def createrawtransaction_tests(self):
assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].createrawtransaction, [], [{'foo': 0}])
assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].createrawtransaction, [], [{address: 'foo'}])
assert_raises_rpc_error(-3, "Amount out of range", self.nodes[0].createrawtransaction, [], [{address: -1}])
assert_raises_rpc_error(-8, "Invalid parameter, duplicated address: %s" % address, self.nodes[0].createrawtransaction, [], [{address: 1}, {address: 1}])
assert_raises_rpc_error(-8, "Invalid parameter, duplicated address and asset: %s" % address, self.nodes[0].createrawtransaction, [], [{address: 1}, {address: 1}])
assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data", self.nodes[0].createrawtransaction, [], [{"data": 'aa'}, {"data": "bb"}])
assert_raises_rpc_error(-1, "JSON value is not an object as expected", self.nodes[0].createrawtransaction, [], [['key-value pair1'], ['2']])

Expand Down