Merge ElementsProject/elements#1010: Support supplying contract hash to issueasset RPC

47d43f14ad Support supplying contract hash to issueasset RPC (Steven Roose)

Pull request description:

  forward port of https://github.com/ElementsProject/elements/pull/993.
  Closes https://github.com/ElementsProject/elements/issues/985.

ACKs for top commit:
  apoelstra:
    ACK 47d43f14ad

Tree-SHA512: e29cda86291c8fe4650595129af477c6dc8648465a5305002ae521bac21a114d6a1c44738786351ac4355eafdcb0da3e4e42c8f204137f9e31e03df20a91db64
This commit is contained in:
Andrew Poelstra 2021-09-16 23:06:17 +00:00
commit 388d47f9a3
No known key found for this signature in database
GPG key ID: C588D63CE41B97C1
4 changed files with 21 additions and 8 deletions

View file

@ -6418,12 +6418,12 @@ static RPCHelpMan issueasset()
{
return RPCHelpMan{"issueasset",
"\nCreate an asset. Must have funds in wallet to do so. Returns asset hex id.\n"
"For more fine-grained control such as non-empty contract-hashes to commit\n"
"to an issuance policy, see `rawissueasset` RPC call.\n",
"For more fine-grained control such as multiple issuances, see `rawissueasset` RPC call.\n",
{
{"assetamount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "Amount of asset to generate. Note that the amount is BTC-like, with 8 decimal places."},
{"tokenamount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "Amount of reissuance tokens to generate. Note that the amount is BTC-like, with 8 decimal places. These will allow you to reissue the asset if in wallet using `reissueasset`. These tokens are not consumed during reissuance."},
{"blind", RPCArg::Type::BOOL , /* default */ "true", "Whether to blind the issuances."},
{"contract_hash", RPCArg::Type::STR_HEX, /* default */ "0000...0000", "Contract hash that is put into issuance definition. Must be 32 bytes worth in hex string form. This will affect the asset id."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@ -6459,6 +6459,12 @@ static RPCHelpMan issueasset()
bool blind_issuances = request.params.size() < 3 || request.params[2].get_bool();
// Check for optional contract to hash into definition
uint256 contract_hash;
if (request.params.size() >= 4) {
contract_hash = ParseHashV(request.params[3], "contract_hash");
}
if (!pwallet->IsLocked())
pwallet->TopUpKeyPool();
@ -6486,13 +6492,14 @@ static RPCHelpMan issueasset()
CAsset dummyasset;
IssuanceDetails issuance_details;
issuance_details.blind_issuance = blind_issuances;
issuance_details.contract_hash = contract_hash;
CTransactionRef tx_ref = SendGenerationTransaction(GetScriptForDestination(asset_dest), asset_dest_blindpub, GetScriptForDestination(token_dest), token_dest_blindpub, nAmount, nTokens, &issuance_details, pwallet);
// Calculate asset type, assumes first vin is used for issuance
CAsset asset;
CAsset token;
CHECK_NONFATAL(!tx_ref->vin.empty());
GenerateAssetEntropy(issuance_details.entropy, tx_ref->vin[0].prevout, uint256());
GenerateAssetEntropy(issuance_details.entropy, tx_ref->vin[0].prevout, issuance_details.contract_hash);
CalculateAsset(asset, issuance_details.entropy);
CalculateReissuanceToken(token, issuance_details.entropy, blind_issuances);
@ -7042,7 +7049,7 @@ static const CRPCCommand commands[] =
{ "wallet", "dumpissuanceblindingkey", &dumpissuanceblindingkey, {"txid", "vin"}},
{ "wallet", "signblock", &signblock, {"blockhex", "witnessScript"}},
{ "wallet", "listissuances", &listissuances, {"asset"}},
{ "wallet", "issueasset", &issueasset, {"assetamount", "tokenamount", "blind"}},
{ "wallet", "issueasset", &issueasset, {"assetamount", "tokenamount", "blind", "contract_hash"}},
{ "wallet", "reissueasset", &reissueasset, {"asset", "assetamount"}},
{ "wallet", "destroyamount", &destroyamount, {"asset", "amount", "comment", "verbose"} },
{ "hidden", "generatepegoutproof", &generatepegoutproof, {"sumkey", "btcpubkey", "onlinepubkey"} },

View file

@ -3679,12 +3679,12 @@ bool CWallet::CreateTransactionInternal(
uint256 entropy;
CAsset asset;
CAsset token;
//TODO take optional contract hash
// Initial issuance always uses vin[0]
GenerateAssetEntropy(entropy, txNew.vin[0].prevout, uint256());
GenerateAssetEntropy(entropy, txNew.vin[0].prevout, issuance_details->contract_hash);
CalculateAsset(asset, entropy);
CalculateReissuanceToken(token, entropy, issuance_details->blind_issuance);
CScript blindingScript(CScript() << OP_RETURN << std::vector<unsigned char>(txNew.vin[0].prevout.hash.begin(), txNew.vin[0].prevout.hash.end()) << txNew.vin[0].prevout.n);
txNew.vin[0].assetIssuance.assetEntropy = issuance_details->contract_hash;
// We're making asset outputs, fill out asset type and issuance input
if (asset_index != -1) {
txNew.vin[0].assetIssuance.nAmount = txNew.vout[asset_index].nValue;

View file

@ -685,7 +685,11 @@ struct CoinSelectionParams
struct IssuanceDetails {
bool issuing = false;
// Indicated fields.
bool blind_issuance = true;
uint256 contract_hash;
// Calculated fields.
CAsset reissuance_asset;
CAsset reissuance_token;
uint256 entropy;

View file

@ -110,7 +110,8 @@ class IssuanceTest(BitcoinTestFramework):
assert_equal(len(self.nodes[0].listissuances()), 0)
# Unblinded issuance of asset
issued = self.nodes[0].issueasset(1, 1, False)
contract_hash = "deadbeef"*8
issued = self.nodes[0].issueasset(1, 1, False, contract_hash)
balance = self.nodes[0].getwalletinfo()["balance"]
assert_equal(balance[issued["asset"]], 1)
assert_equal(balance[issued["token"]], 1)
@ -120,7 +121,8 @@ class IssuanceTest(BitcoinTestFramework):
self.nodes[0].generate(1)
self.sync_all()
issued2 = self.nodes[0].issueasset(2, 1)
contract_hash = "deadbeee"*8
issued2 = self.nodes[0].issueasset(2, 1, True, contract_hash)
test_asset = issued2["asset"]
assert_equal(self.nodes[0].getwalletinfo()['balance'][test_asset], Decimal(2))
node1balance = self.nodes[1].getwalletinfo()['balance']