mirror of
https://github.com/bitcoin/bips.git
synced 2025-03-04 03:03:53 +01:00
bip-tap: BIPs for the Taproot Assets Protocol
This commit is contained in:
parent
e643d247c8
commit
c156b7691d
23 changed files with 94843 additions and 0 deletions
182
bip-tap-addr.mediawiki
Normal file
182
bip-tap-addr.mediawiki
Normal file
|
@ -0,0 +1,182 @@
|
|||
<pre>
|
||||
BIP: ???
|
||||
Layer: Applications
|
||||
Title: Taproot Asset On Chain Addresses
|
||||
Author: Olaoluwa Osuntokun <laolu32@gmail.com>
|
||||
Comments-Summary: No comments yet.
|
||||
Comments-URI: https://git
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Created: 2021-12-10
|
||||
License: BSD-2-Clause
|
||||
</pre>
|
||||
|
||||
==Abstract==
|
||||
|
||||
This document describes a way to map a single-asset Taproot Asset send to a
|
||||
familiar <code>bech32m</code> address, as well as a way to map that address into
|
||||
a valid Taproot Asset script tree that can be included in a broadcast
|
||||
transaction to complete a transfer.
|
||||
Once the transaction has been broadcast, the receiver can use the
|
||||
previous outpoint of the confirmed transaction to lookup the complete asset
|
||||
proof in their chosen Universe.
|
||||
|
||||
==Copyright==
|
||||
|
||||
This document is licensed under the 2-clause BSD license.
|
||||
|
||||
==Motivation==
|
||||
|
||||
The Taproot Asset protocol needs an easy way to allow users to send each other
|
||||
assets on-chain, without requiring several rounds of interaction to exchange and
|
||||
validate proofs. By using the existing <code>bech32m</code> address
|
||||
serialization standard, such addresses look distinct, while also looking
|
||||
familiar enough based on the character set encoding. The described address
|
||||
format also addresses a number of possible foot guns, by making it impossible
|
||||
to send the wrong asset (based on an address) amongst other protections.
|
||||
|
||||
==Specification==
|
||||
|
||||
A Taproot Asset is uniquely defined by its <code>asset_genesis</code> as well as
|
||||
the <code>asset_script_key</code> that serves as a predicate that must be
|
||||
satisfied for transfers. These values, along with an internal Taproot key used
|
||||
when creating the Bitcoin output that holds the Taproot Asset, are encoded into
|
||||
a single address.
|
||||
|
||||
===Encoding an Address===
|
||||
|
||||
Let the human readable prefix (as specified by BIP 173) be:
|
||||
|
||||
* <code>tapbc</code> for mainnet
|
||||
* <code>taptb</code> for testnet
|
||||
* <code>taprt</code> for regtest
|
||||
* <code>taptb</code> for the public signet
|
||||
* <code>tapsb</code> for simnet
|
||||
|
||||
We refer to this value as the <code>taproot_asset_hrp</code>
|
||||
|
||||
Given the 32-byte <code>asset_id</code>, 33-byte compressed
|
||||
<code>asset_script_key</code>, and 33-byte compressed internal public
|
||||
key, 8-byte amount to send, an address is encoded as:
|
||||
* <code>bech32m(hrp=taproot_asset_hrp, addr_tlv_payload)</code>
|
||||
|
||||
where <code>addr_tlv_payload</code> is a TLV payload composed of the following
|
||||
types:
|
||||
* type: 0 (<code>taproot_asset_version</code>)
|
||||
** value:
|
||||
*** [<code>u8</code>:<code>version</code>]
|
||||
* type: 2 (<code>asset_id</code>)
|
||||
** value:
|
||||
*** [<code>32*byte</code>:<code>asset_id</code>]
|
||||
* type: 3 (<code>asset_key_family</code>)
|
||||
** value:
|
||||
*** [<code>33*byte</code>:<code>family_key</code>]
|
||||
* type: 4 (<code>asset_script_key</code>)
|
||||
** value:
|
||||
*** [<code>33*byte</code>:<code>script_key</code>]
|
||||
* type: 6 (<code>internal_key</code>)
|
||||
** value:
|
||||
*** [<code>33*byte</code>:<code>taproot_internal_key</code>]
|
||||
* type: 7 (<code>taproot_sibling_preimage</code>)
|
||||
** value:
|
||||
*** [<code>...*byte</code>:<code>tapscript_preimage</code>]
|
||||
* type: 8 (<code>amt</code>)
|
||||
** value:
|
||||
*** [<code>BigSize</code>:<code>amt_to_send</code>]
|
||||
* type: 10 (<code>proof_courier_addr</code>)
|
||||
** value:
|
||||
*** [<code>...*byte</code>:<code>proof_courier_addr</code>]
|
||||
|
||||
Inspired by Lightning's BOLT specification, we adopt the "it's OK to be odd"
|
||||
semantics here as well. This enables receivers to specify to the caller certain
|
||||
information that MUST be known in order to properly complete a transfer.
|
||||
|
||||
The only odd keys specified in the current version are the
|
||||
<code>asset_key_family</code> type and the <code>asset_type</code> field. The
|
||||
<code>asset_key_family</code> field isn't always needed for assets that don't
|
||||
allow for continual re-issuance. Similarly, if the <code>asset_type</code>
|
||||
field isn't specified, then one can assume a normal asset is being sent.
|
||||
|
||||
The <code>proof_courier_addr</code> is a mandatory URI (RFC 3986) that indicates
|
||||
what proof courier to use when sending the proofs from the sender to the
|
||||
recipient. The scheme (protocol) indicates the type of courier transport to use,
|
||||
current valid values are <code>hashmail://</code> for Hashmail based couriers
|
||||
and <code>universerpc://</code> for gRPC based transfer via a universe server.
|
||||
|
||||
===Decoding and Sending To An Address===
|
||||
|
||||
Given a valid Taproot Asset address, decompose the contents into the referenced
|
||||
<code>asset_id</code>, <code>asset_script_key</code>, and
|
||||
<code>internal_key</code>. Look up the full <code>asset_genesis</code> with the
|
||||
<code>asset_id</code> in the appropriate Universe.
|
||||
|
||||
Construct a new blank Taproot Asset leaf according to the default
|
||||
[[./bip-tap.mediawiki#asset-leaf-format|Asset Leaf Format]] with the following
|
||||
values being set explicitly (and all other values being their default/zero
|
||||
values):
|
||||
* <code>taproot_asset_version</code>: <code>0</code>
|
||||
* <code>asset_genesis</code>: <code>asset_genesis</code>
|
||||
* <code>amt</code>: <code>amt_to_send</code>
|
||||
* <code>asset_script_version</code>: <code>0</code>
|
||||
* <code>asset_script_key</code>: <code>asset_script_key</code>
|
||||
* <code>asset_key_family</code>: <code>asset_key_family</code>
|
||||
|
||||
Create a valid tapscript root, using leaf version <code>0x0c</code> with the
|
||||
sole leaf being the serialized TLV blob specified above.
|
||||
|
||||
Create the top-level taproot public key script, as a segwit v1 witness
|
||||
program, as specified in BIP 341, using the included key as the internal key.
|
||||
|
||||
With the target taproot public key script constructed, the asset is sent to the
|
||||
receiver with the execution of the following steps:
|
||||
# Construct a valid transaction that spends an input that holds the referenced <code>asset_id</code> and ''exactly'' <code>amt</code> units of the asset.
|
||||
# Create a new Taproot Asset output commitment based on the input commitment (this will be the change output), that now only commits to <code>S-A</code> units of <code>asset_id</code>, where <code>S</code> is the input amount, and <code>A</code> is the amount specified in the encoded Taproot Asset address.
|
||||
## This new leaf MUST have a <code>split_commitment</code> specified that commits to the position (keyed by <code>sha256(output_index || asset_id || asset_script_key)</code> within the transaction of the newly created asset leaf for the receiver. This split commitment is omitted by the sender when serializing the leaf for inclusion in the asset tree, otherwise the tree wouldn't be predictable on the receiver side. This has a corresponding rule in the [[./bip-tap-vm.mediawiki|bip-tap-vm]] during the input mapping of the inclusion proof validation.
|
||||
## Add an additional output that sends a de minimis (in practice this MUST be above dust) amount to the top-level taproot public key computed earlier.
|
||||
## Broadcast and sign the transaction, submitting the resulting Taproot Asset state transition proof to a Universe of choice, also known by the receiver.
|
||||
# Post the resulting state transition proof to the specified Universe. The submitted proof ''must'' contain the optional auxiliary value of the full <code>split_commitment</code> the receiver requires to spend the asset.
|
||||
|
||||
===Non-interactive full value send===
|
||||
|
||||
Sending assets to an address is inherently a non-interactive process as there is
|
||||
no active communication between the sender and recipient other than the exchange
|
||||
of the address in the first place.
|
||||
Because of the above mentioned requirement that an asset leaf created to send to
|
||||
an address MUST have a <code>split_commitment</code>, a special case exists if
|
||||
there is no change going back to the sender (an asset output is fully consumed
|
||||
by the transfer to an address): A special ''tombstone'' output with a value of
|
||||
0 must be created for the split root asset (the <code>root_asset</code> of the
|
||||
split) that holds the transfer witness. The <code>script_key</code> of the
|
||||
split root asset output should be the well-known NUMS point (using the string
|
||||
"taproot-assets" and the traditional "hash and increment" approach to generating
|
||||
the point) to prove the output cannot be spent further. Such a tombstone output
|
||||
can then be pruned from the tree when the UTXO is spent further.
|
||||
More details about interactive and non-interactive sends and tombstone outputs
|
||||
can be found in the [[./bip-tap-psbt.mediawiki|bip-tap-psbt]].
|
||||
|
||||
===Spending The Received Asset===
|
||||
|
||||
In order to spend (or simply confirm receipt) of the received asset, the
|
||||
receiver should:
|
||||
# Re-derive the taproot public key script created above that sends to their specified Taproot Asset leaf.
|
||||
# Wait for a transaction creating the output to be confirmed in the blockchain.
|
||||
## In practice this may be via light client protocols such as BIP 157/158, or simply a full node with an address index, or import public key.
|
||||
# For each previous outpoint referenced in the transaction:
|
||||
## Look up the previous outpoint as a key into the chosen canonical Universe/Multiverse.
|
||||
### If the key is found, verify the inclusion proof of the value (as described in [[./bip-tap-proof-file.mediawiki|bip-tap-proof-file]]), and extract the <code>split_commitment</code> inclusion proof for the output.
|
||||
# Walk the Universe tree backwards in time to incrementally construct the full provenance proof needed to spend the asset.
|
||||
|
||||
==Test Vectors==
|
||||
|
||||
Test vectors for [[Encoding an Address]] can be found here:
|
||||
* [[bip-tap-addr/address_tlv_encoding_generated.json|Address TLV encoding test vectors]]
|
||||
* [[bip-tap-addr/address_tlv_encoding_error_cases.json|Address TLV encoding error test vectors]]
|
||||
|
||||
The test vectors are automatically generated by
|
||||
[https://github.com/lightninglabs/taproot-assets/tree/main/address unit tests in
|
||||
the Taproot Assets GitHub repository].
|
||||
|
||||
==Reference Implementation==
|
||||
|
||||
github.com/lightninglabs/taproot-assets/tree/main/address
|
||||
|
65
bip-tap-addr/address_tlv_encoding_error_cases.json
Normal file
65
bip-tap-addr/address_tlv_encoding_error_cases.json
Normal file
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
"error_test_cases": [
|
||||
{
|
||||
"address": {},
|
||||
"error": "missing chain params HRP"
|
||||
},
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "bc"
|
||||
},
|
||||
"error": "invalid chain params HRP"
|
||||
},
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "tapbc"
|
||||
},
|
||||
"error": "missing asset ID"
|
||||
},
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "tapbc",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"error": "missing script key"
|
||||
},
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "tapbc",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"error": "invalid script key length",
|
||||
"comment": "script key must be 33 bytes (compressed)"
|
||||
},
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "tapbc",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"error": "missing internal key"
|
||||
},
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "tapbc",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"internal_key": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"error": "invalid internal key length",
|
||||
"comment": "internal key must be 33 bytes (compressed)"
|
||||
},
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "tapbc",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"internal_key": "000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"group_key": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"error": "invalid group key length",
|
||||
"comment": "group key must be 33 bytes (compressed)"
|
||||
}
|
||||
]
|
||||
}
|
110
bip-tap-addr/address_tlv_encoding_generated.json
Normal file
110
bip-tap-addr/address_tlv_encoding_generated.json
Normal file
|
@ -0,0 +1,110 @@
|
|||
{
|
||||
"valid_test_cases": [
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "taprt",
|
||||
"asset_version": 0,
|
||||
"asset_id": "7a3811630bb33503c6536c3a223d3caecb93fe55f4b3439528edf27b10d38e93",
|
||||
"group_key": "",
|
||||
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"tapscript_sibling": "",
|
||||
"amount": 5577006791947779410,
|
||||
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
|
||||
},
|
||||
"expected": "taprt1qqqsqq3q0gupzcctkv6s83jndsazy0fu4m9e8lj47je589fgahe8kyxn36fsgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78ssz0lf4jcygg8ln74yz32dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xseszxcn5n",
|
||||
"comment": "valid regtest address"
|
||||
},
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "tapsb",
|
||||
"asset_version": 0,
|
||||
"asset_id": "8acb5154261425dd613fda19dee00a51e95c6921df8af4085bc468706b946fec",
|
||||
"group_key": "",
|
||||
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"tapscript_sibling": "",
|
||||
"amount": 3510942875414458836,
|
||||
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
|
||||
},
|
||||
"expected": "tapsb1qqqsqq3q3t94z4pxzsja6cflmgvaacq22854c6fpm790gzzmc358q6u5dlkqgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78ssz0lxzu4luvrc3cagz32dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xses89l6tn",
|
||||
"comment": "valid simnet address"
|
||||
},
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "taptb",
|
||||
"asset_version": 0,
|
||||
"asset_id": "60459cbb4d4e6a78b8c58545f2fe026ad217bf0fafeed5ff5e3b3379c658ddf3",
|
||||
"group_key": "",
|
||||
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"tapscript_sibling": "",
|
||||
"amount": 2740103009342231109,
|
||||
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
|
||||
},
|
||||
"expected": "taptb1qqqsqq3qvpzeew6dfe483wx9s4zl9lszdtfp00c04lhdtl678vehn3jcmhesgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78ssz0lycrv626h62fy2z32dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xsesdgef4w",
|
||||
"comment": "valid testnet address"
|
||||
},
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "tapbc",
|
||||
"asset_version": 0,
|
||||
"asset_id": "f2c70e1261b761f098499918acf6ccf18d7d9cf7cd6be0c940630f0643ab832c",
|
||||
"group_key": "",
|
||||
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"tapscript_sibling": "",
|
||||
"amount": 545291762129038907,
|
||||
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
|
||||
},
|
||||
"expected": "tapbc1qqqsqq3q7trsuynpkaslpxzfnyv2eakv7xxhm88he447pj2qvv8svsatsvkqgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78ssz0lq7g58al55hhrkz32dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xsesu23fxd",
|
||||
"comment": "valid mainnet address"
|
||||
},
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "taptb",
|
||||
"asset_version": 0,
|
||||
"asset_id": "7f3a94b3048ecbce4f2b1686e2df89bde52d5ead1aed011f75fa6578dcab0839",
|
||||
"group_key": "03f32d239904d1addae728d1917a94bc1d20455b12b251a9222d035e5014a9f759",
|
||||
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"tapscript_sibling": "",
|
||||
"amount": 1,
|
||||
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
|
||||
},
|
||||
"expected": "taptb1qqqsqq3q0uaffvcy3m9uunetz6rw9hufhhjj6h4drtksz8m4lfjh3h9tpqusxggr7vkj8xgy6xka4eeg6xgh499ur5sy2kcjkfg6jg3dqd09q99f7avsgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78ssqgppg4xsctndpkkz6tv8ghj7unpdejzu6rpwd5x6ctfdsh8qun0danzucm0w4exjetj8g6rgvcxm4yl6",
|
||||
"comment": "signet group collectible"
|
||||
},
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "tapsb",
|
||||
"asset_version": 0,
|
||||
"asset_id": "7da00bc74bfe9791807fa20dbeec226348904e6bfa8c10ab434922369e4d4747",
|
||||
"group_key": "",
|
||||
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"tapscript_sibling": "",
|
||||
"amount": 1,
|
||||
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
|
||||
},
|
||||
"expected": "tapsb1qqqsqq3q0ksqh36tl6terqrl5gxmampzvdyfqnntl2xpp26rfy3rd8jdgarsgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78ssqgppg4xsctndpkkz6tv8ghj7unpdejzu6rpwd5x6ctfdsh8qun0danzucm0w4exjetj8g6rgvcvmghpa",
|
||||
"comment": "simnet collectible"
|
||||
},
|
||||
{
|
||||
"address": {
|
||||
"chain_params_hrp": "tapsb",
|
||||
"asset_version": 0,
|
||||
"asset_id": "b603ddaafac3b6253de23ae01935f108bee96363eddf77456c0e24ed6a67650f",
|
||||
"group_key": "",
|
||||
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"tapscript_sibling": "00c0126e6f7420612076616c696420736372697074",
|
||||
"amount": 1,
|
||||
"proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443"
|
||||
},
|
||||
"expected": "tapsb1qqqsqq3qkcpam2h6cwmz200z8tspjd03pzlwjcmrah0hw3tvpcjw66n8v58sgggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78svggz5zh7k9jlpmpk3q9k3c9640v6m8rzl5dxn25e30psax35vgpwq78sw9gqcqfxumm5ypsjqanpd35kggrnvdexjur5pqqszz32dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xseswj02c5",
|
||||
"comment": "simnet collectible with sibling"
|
||||
}
|
||||
],
|
||||
"error_test_cases": null
|
||||
}
|
323
bip-tap-ms-smt.mediawiki
Normal file
323
bip-tap-ms-smt.mediawiki
Normal file
|
@ -0,0 +1,323 @@
|
|||
<pre>
|
||||
BIP: ???
|
||||
Layer: Applications
|
||||
Title: Merkle Sum Sparse Merkle Trees
|
||||
Author: Olaoluwa Osuntokun <laolu32@gmail.com>
|
||||
Comments-Summary: No comments yet.
|
||||
Comments-URI: https://git
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Created: 2021-12-10
|
||||
License: BSD-2-Clause
|
||||
</pre>
|
||||
|
||||
==Abstract==
|
||||
|
||||
This document describes a merkle-sum sparse merkle tree (MS-SMT) data
|
||||
structure. This is an augmented version of a sparse merkle tree that includes
|
||||
a sum value which is combined during the internal branch hashing operation.
|
||||
Such trees permit efficient proofs of non-inclusion, while also supporting
|
||||
efficient fault proofs of invalid merkle sum commitments.
|
||||
|
||||
==Copyright==
|
||||
|
||||
This document is licensed under the 2-clause BSD license.
|
||||
|
||||
==Motivation==
|
||||
|
||||
Taproot Assets are a Taproot-native asset overlay protocol. Rather than post all
|
||||
asset related data on-chain in <code>OP_RETURN</code> outputs, the protocol
|
||||
instead uses a series of commitments anchored within the Taproot script tree.
|
||||
When handling unique assets, it's important to be able to prove that the former
|
||||
owner (or seller) of the asset is no longer committing to it within their tree.
|
||||
Additionally, when carrying out multi-asset swaps, verifiers need to be able to
|
||||
efficiently verify that no new assets are being created (inflation check). The
|
||||
MS-SMT supports both non-inclusion proofs, and non-inflation proofs.
|
||||
|
||||
==Design==
|
||||
|
||||
A merkle sum tree is a merkalized key-value map simulated over a particia
|
||||
merkle tree of depth 256 (as we use sha256 as our hash function). The "base"
|
||||
state of the tree, is a merkle tree with 2^256 leaves, storing an "empty hash".
|
||||
Within this tree, the digests of an empty leaf, and empty internal nodes for
|
||||
each level can be computed ahead of time. The "value" of an empty leaf is zero.
|
||||
|
||||
In addition to storing the hash digest of a leaf/branch, an 8-byte value is
|
||||
also stored along side the entry, making each entry 40 bytes in length. The
|
||||
root hash therefore commits to the digest of all items in the leaf, as well as
|
||||
the sum of all the "sum values" in the set of leaves. When combining two
|
||||
branches/leaves, the sum of the left and right leaf/branch is serialized along
|
||||
with the hash digest of the nodes.
|
||||
|
||||
When inserting a new key into the tree, at each level, the ith bit of the key
|
||||
is used to traverse left or right down the tree. Due to this traversal, every
|
||||
possible key has a unique location (position wise) within the set of leaves. A
|
||||
non-inclusion proof is the proof that the value at the unique position for a
|
||||
key is empty.
|
||||
|
||||
Due to the nature of the mapping, sparse merkle trees are ''history
|
||||
independent'' meaning no matter the inserting order, given the same set of keys
|
||||
and values, the same root hash will always be produced. As the size of the
|
||||
tree is intractable, a series of techniques are used to maintain a relevant set
|
||||
of branches and leaves in memory, using a persistent key-value store to store
|
||||
the relevant unique items of the tree. Proofs can be compressed by using a
|
||||
bitmap to indicate if the next node in the proof is an empty hash for that
|
||||
level, or the parent of the item being proved.
|
||||
|
||||
===Specification===
|
||||
|
||||
We use <code>sha256</code> as our hash function, and 8-byte sum values.
|
||||
|
||||
====Building the Empty Hash Map====
|
||||
|
||||
The map of all empty hashes by level <code>empty_hashes</code> can be
|
||||
pre-computed ahead of time, as:
|
||||
* The hash of an empty leaf is <code>empty_hash_1 = sha256(nil, nil)</code>
|
||||
* The hash of an empty branch at the second level is <code>empty_hash_2 = sha256(empty_hash_1, empty_hash_1)</code>
|
||||
* and so on...
|
||||
|
||||
We refer to the map resulting from this route as the
|
||||
<code>empty_hash_map</code>:
|
||||
<source lang="python">
|
||||
build_empty_hash_map() -> map[int][32]byte:
|
||||
|
||||
empty_hash_map = make(map[int][32]byte)
|
||||
prior_level_hash = None
|
||||
for i in range(256):
|
||||
if prior_level_hash is None:
|
||||
prior_level_hash = sha256(nil, nil, 0)
|
||||
empty_hash_map[i] = prior_level_hash
|
||||
continue
|
||||
|
||||
empty_hash_map[i] = sha256(prior_level_hash, prior_level_hash, 0)
|
||||
|
||||
return empty_hash_map
|
||||
|
||||
</source>
|
||||
|
||||
====Node Digest Computation===
|
||||
|
||||
The MS-SMT tree has two types of nodes: leaf nodes and branch nodes.
|
||||
|
||||
The digest of a leaf node is a function of the <code>sum_value</code> (encoded
|
||||
as a big-endian integer) of the leaf node and it's actual <code>value</code>:
|
||||
|
||||
<source lang="python">
|
||||
leaf_node_digest(leaf_node: MerkleSumLeaf) -> [32]byte:
|
||||
h = new_sha_writer()
|
||||
h.write_bytes(leaf_node.value)
|
||||
h.write_big_endian_int(leaf_node.sum_value)
|
||||
|
||||
return h.bytes()
|
||||
</source>
|
||||
|
||||
The digest of a branch node commits to the digest of its two children (which
|
||||
may be another branch or a leaf), and also commits to the _sum_ of their
|
||||
respective <code>sum_value</code>s:
|
||||
|
||||
<source lang="python">
|
||||
node_digest(node: Node) -> [32]byte
|
||||
match node:
|
||||
case MerkleSumLeaf:
|
||||
return leaf_node_digest(node)
|
||||
|
||||
case MerkleSumBranch:
|
||||
return branch_node_digest(node)
|
||||
|
||||
branch_node_digest(left: Node, right: Node) -> [32]byte
|
||||
left_digest = node_digest(left)
|
||||
right_digest = node_digest(right)
|
||||
new_sum = left.sum_value() + right_sum_value()
|
||||
|
||||
h = new_sha_writer()
|
||||
h.write_bytes(left_digest)
|
||||
h.write_bytes(right_digest)
|
||||
h.write_big_endian_int(new_sum)
|
||||
|
||||
return h.bytes()
|
||||
</source>
|
||||
|
||||
====Looking Up Items====
|
||||
|
||||
Looking up an item in the tree requires traversal down the tree based on the
|
||||
next bit position of the key itself. We assume the existence of a persistent
|
||||
key-value store that maps the hash of a node to the left and right digests of
|
||||
its children.
|
||||
|
||||
The following routine specifies the lookup algorithm:
|
||||
<source lang="python">
|
||||
lookup_item(key [32]byte, db KVStore) -> MerkleSumLeaf:
|
||||
|
||||
root_hash, _ = db.fetch_root_hash()
|
||||
current_branch = root_hash
|
||||
|
||||
value_hash, value_sum = None
|
||||
for i in range(256):
|
||||
if bit_index(i, key) == 0:
|
||||
current_branch, _ = db.get_children(current_branch)
|
||||
else:
|
||||
_, current_branch = db.get_children(current_branch)
|
||||
|
||||
return MerkleSumLeaf(current_branch.hash, current_branch)
|
||||
|
||||
</source>
|
||||
|
||||
====Inserting Items====
|
||||
|
||||
Inserting items into the tree entails traversing the tree until we arrive at
|
||||
the position for the leaf, then bubbling up (hashing and summing) the change
|
||||
all the way up the tree.
|
||||
|
||||
<source lang="python">
|
||||
insert_item(key [32]byte, value []byte, sum_value int64, db KVStore) -> None:
|
||||
root_hash, _ = db.fetch_root_hash()
|
||||
current_branch = root_hash
|
||||
|
||||
insertion_path = []
|
||||
value_hash, value_sum = None
|
||||
for i in range(256):
|
||||
if bit_index(i, key) == 0:
|
||||
current_branch, sibling = db.get_children(current_branch)
|
||||
insertion_path.append(sibling)
|
||||
else:
|
||||
sibling, current_branch, = db.get_children(current_branch)
|
||||
insertion_path.append(sibling)
|
||||
|
||||
db.insert(current_branch.parent_hash, MerkleSumLeaf(key, value, sum_value))
|
||||
|
||||
for i in range(256):
|
||||
updated_sum = sum_value + inclusion_path[-1].value
|
||||
|
||||
sibling_node = insertion_path[-1]
|
||||
if bit_index(i, key) == 0:
|
||||
updated_value = sha256(value, sibling_node.sum_value, updated_sum)
|
||||
|
||||
db.insert(key=updated_value, value=(sibling_node, value))
|
||||
else:
|
||||
updated_value = sha256(insertion_path[-1].hash, value, updated_sum)
|
||||
|
||||
db.insert(key=updated_value, value=(value, sibling_node))
|
||||
|
||||
value = updated_value
|
||||
sum_value = updated_sum
|
||||
|
||||
insertion_path.pop()
|
||||
|
||||
return None
|
||||
</source>
|
||||
|
||||
|
||||
====Deleting Items====
|
||||
|
||||
Deleting an item is identical to insertion, but we delete the item in the tree
|
||||
by setting its value to the empty hash.
|
||||
<source lang="python">
|
||||
delete_item(key [32]byte, db KVStore) -> None:
|
||||
return insert_item(key, nil, 0, db)
|
||||
</source>
|
||||
|
||||
====Creating Inclusion & Non-Inclusion Proofs====
|
||||
|
||||
An inclusion proof of an item proves that the item is found in the tree, and
|
||||
has a certain sum value. A non-inclusion tree proves the opposite: that an item
|
||||
is not found within the tree.
|
||||
|
||||
Generating an inclusion or non inclusion proof entails walking down the tree
|
||||
and obtaining all the sibling hashes and their sum values:
|
||||
<source lang="python">
|
||||
gen_merkle_proof(key [32]byte, db KVStore) -> []MerkleSumNode
|
||||
root_hash, _ = db.fetch_root_hash()
|
||||
current_branch = root_hash
|
||||
|
||||
proof_nodes = []
|
||||
value_hash, value_sum = None
|
||||
for i in range(256):
|
||||
if bit_index(i, key) == 0:
|
||||
current_branch, sibling = db.get_children(current_branch)
|
||||
proof_nodes.append(sibling)
|
||||
else:
|
||||
sibling, current_branch, = db.get_children(current_branch)
|
||||
proof_nodes.append(sibling)
|
||||
|
||||
return proof_nodes
|
||||
</source>
|
||||
|
||||
A plain proof is always a series of 256 merkle sum elements. However we can
|
||||
compress proofs by using an extra bitmap that indicates if the proof contents
|
||||
are an empty hash or not.
|
||||
<source lang="python">
|
||||
compress_merkle_proof(proof []MerkleSumNode) -> CompressedProof:
|
||||
compressed_proof = new_compressed_proof(
|
||||
compression_bits=new_bit_vector(256),
|
||||
proof=[]MerkleSumNode{},
|
||||
)
|
||||
|
||||
for i, proof_node in proof:
|
||||
if proof_node == empty_hash_map[i]:
|
||||
compressed_proof.compression_bits.append(1)
|
||||
else:
|
||||
compressed_proof.proof.append(proof_node)
|
||||
|
||||
return compressed_proof
|
||||
</source>
|
||||
|
||||
====Verifying Inclusion & Non-Inclusion Proofs====
|
||||
|
||||
In order to verify a proof, we need to confirm that if starting at the proof,
|
||||
if we hash and sum up the tree, then we'll end up at the same root hash and sum
|
||||
value.
|
||||
|
||||
Before proofs are verified, the proof should first be decompressed:
|
||||
<source lang="python">
|
||||
decompress_merkle_proof(compressed_proof CompressedProof) -> []MerkleSumNode:
|
||||
proof = []MerkleSumNode{}
|
||||
|
||||
for i in range(256):
|
||||
if compressed_proof.bit_at(index=i) == 1:
|
||||
proof.append(empty_hash_map[i])
|
||||
else:
|
||||
proof.append(compressed_proof.proof)
|
||||
compressed_proof = drop_1(compressed_proof.proof)
|
||||
|
||||
return proof
|
||||
</source>
|
||||
|
||||
With the proof decompressed, we verify the proof by hashing and summing up each
|
||||
level.
|
||||
<source lang="python">
|
||||
verify_merkle_proof(proof []MerkleSumNode, root MerkleSumNode,
|
||||
key [32]byte, value []byte, value_sum int64) -> bool:
|
||||
|
||||
for i in range(256):
|
||||
if bit_index(i, key) == 0:
|
||||
value = sha256(proof[-1-i], value, proof[1-i].sum, value_sum)
|
||||
else:
|
||||
value = sha256(value, proof[-1-i], value.sum, value_sum)
|
||||
|
||||
return root.hash == value && root.sum == value_sum
|
||||
|
||||
</source>
|
||||
|
||||
|
||||
====Caching Optimizations====
|
||||
|
||||
TODO(roasbeef):
|
||||
|
||||
|
||||
==Test Vectors==
|
||||
|
||||
Test vectors for Merkle Sum Sparse Merkle Trees can be found here:
|
||||
* [[bip-tap-ms-smt/mssmt_tree_deletion.json|MS-SMT leaf deletion test vectors]]
|
||||
* [[bip-tap-ms-smt/mssmt_tree_error_cases.json|Tree error test vectors]]
|
||||
* [[bip-tap-ms-smt/mssmt_tree_proofs.json|MS-SMT proof test vectors]]
|
||||
* [[bip-tap-ms-smt/mssmt_tree_replacement.json|MS-SMT leaf replacement test vectors]]
|
||||
|
||||
The test vectors are automatically generated by
|
||||
[https://github.com/lightninglabs/taproot-assets/tree/main/mssmt unit tests in
|
||||
the Taproot Assets GitHub repository].
|
||||
|
||||
==Backwards Compatibility==
|
||||
|
||||
==Reference Implementation==
|
||||
|
||||
github.com/lightninglabs/taproot-assets/tree/main/mssmt
|
45
bip-tap-ms-smt/mssmt_tree_deletion.json
Normal file
45
bip-tap-ms-smt/mssmt_tree_deletion.json
Normal file
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"all_tree_leaves": [
|
||||
{
|
||||
"key": "0100000000000000000000000000000000000000000000000000000000000000",
|
||||
"node": {
|
||||
"value": "4f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64981855ad8681d0d86d1e91e00167939cb6694d2c422acd208a0072939487f6999eb9d18a44784045d87f3c67cf22746e995af5a25367951baa2ff6cd471c4",
|
||||
"sum": "2775174756"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "0200000000000000000000000000000000000000000000000000000000000000",
|
||||
"node": {
|
||||
"value": "7723b9faf9c51fd5d5788bb39d3c068fa6807d30f6201d3f6dfd31715d08b1733440cde1049608d23c4e45c5ed61f863350232f85827e7c292dc5f1eced1cbc912e3f5c420bd945911d3881ede5153d3b2cc85371fff98d2caf97cad6ef590014017f9690cab08989851",
|
||||
"sum": "2977921451"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "0400000000000000000000000000000000000000000000000000000000000000",
|
||||
"node": {
|
||||
"value": "79f8f54e3133fc2cdef259df2ba0d48f37bf9e43792e3a777214cf4aab6dde6deeb543a8813b71b5974136c1220d6218a252881f0f5677ff5b6aba127f19a5f3c5aac988543d7839a90a3f947c4e4d5c6ae1ab48dbd40456d1aa65339a4c15eb520e8ff9f965ac4c37735937cf09942e7958f8a6cddee41707423f715903ffe0d15af8c3140d3a736d23be7485fceb9f07c6509f2c506eda4ec9d30ccc133708f48d8828e332808c84a745d337296d871b9794de1c5d06534aaf65587526a84e2521f8b332645e0e72564bb308ecf99b7bc69608474389d1",
|
||||
"sum": "3351083531"
|
||||
}
|
||||
}
|
||||
],
|
||||
"valid_test_cases": [
|
||||
{
|
||||
"root_hash": "c290ff98be50aa38892c07d61b41ff20e19b76d46cbe993d0c3e87411d0d1af6",
|
||||
"root_sum": "2775174756",
|
||||
"inserted_leaves": [
|
||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
||||
"0200000000000000000000000000000000000000000000000000000000000000",
|
||||
"0400000000000000000000000000000000000000000000000000000000000000"
|
||||
],
|
||||
"deleted_leaves": [
|
||||
"0200000000000000000000000000000000000000000000000000000000000000",
|
||||
"0400000000000000000000000000000000000000000000000000000000000000"
|
||||
],
|
||||
"replaced_leaves": null,
|
||||
"inclusion_proofs": null,
|
||||
"exclusion_proofs": null,
|
||||
"comment": "sub tree deletion"
|
||||
}
|
||||
],
|
||||
"error_test_cases": null
|
||||
}
|
42
bip-tap-ms-smt/mssmt_tree_error_cases.json
Normal file
42
bip-tap-ms-smt/mssmt_tree_error_cases.json
Normal file
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"all_tree_leaves": [
|
||||
{
|
||||
"key": "5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64981855ad8681d0d86d1e9",
|
||||
"node": {
|
||||
"value": "52fdfc072182654f163f",
|
||||
"sum": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "1e00167939cb6694d2c422acd208a0072939487f6999eb9d18a44784045d87f3",
|
||||
"node": {
|
||||
"value": "52fdfc072182654f163f",
|
||||
"sum": "18446744073709551615"
|
||||
}
|
||||
}
|
||||
],
|
||||
"valid_test_cases": [
|
||||
{
|
||||
"root_hash": "3aef57ab466f3b8eebd90dc155816684553fc5f8888ffa95fe9944ee5a71c8ea",
|
||||
"root_sum": "1",
|
||||
"inserted_leaves": [
|
||||
"5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64981855ad8681d0d86d1e9"
|
||||
],
|
||||
"deleted_leaves": null,
|
||||
"replaced_leaves": null,
|
||||
"inclusion_proofs": null,
|
||||
"exclusion_proofs": null,
|
||||
"comment": "non overflowing leaf"
|
||||
}
|
||||
],
|
||||
"error_test_cases": [
|
||||
{
|
||||
"inserted_leaves": [
|
||||
"5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64981855ad8681d0d86d1e9",
|
||||
"1e00167939cb6694d2c422acd208a0072939487f6999eb9d18a44784045d87f3"
|
||||
],
|
||||
"error": "integer overflow",
|
||||
"comment": "overflowing leaf"
|
||||
}
|
||||
]
|
||||
}
|
84060
bip-tap-ms-smt/mssmt_tree_proofs.json
Normal file
84060
bip-tap-ms-smt/mssmt_tree_proofs.json
Normal file
File diff suppressed because it is too large
Load diff
1519
bip-tap-ms-smt/mssmt_tree_replacement.json
Normal file
1519
bip-tap-ms-smt/mssmt_tree_replacement.json
Normal file
File diff suppressed because it is too large
Load diff
324
bip-tap-proof-file.mediawiki
Normal file
324
bip-tap-proof-file.mediawiki
Normal file
|
@ -0,0 +1,324 @@
|
|||
<pre>
|
||||
BIP: ???
|
||||
Layer: Applications
|
||||
Title: Taproot Asset Flat File Proof Format
|
||||
Author: Olaoluwa Osuntokun <laolu32@gmail.com>
|
||||
Comments-Summary: No comments yet.
|
||||
Comments-URI: https://git
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Created: 2021-12-10
|
||||
License: BSD-2-Clause
|
||||
</pre>
|
||||
|
||||
==Abstract==
|
||||
|
||||
This document defines a flat file proof format as a standardized way to package
|
||||
Taproot Asset proofs. The proof format itself is an append-only log of the prior
|
||||
lineage of a given asset. Proofs are anchored at the initial "genesis output"
|
||||
for a given asset. A proof of a single Taproot Asset state transition includes a
|
||||
Bitcoin merkle proof, a Taproot Asset merkle-sum sparse merkle tree (MS-SMT)
|
||||
inclusion proof, and finally a set of valid witnesses for the state transition.
|
||||
|
||||
==Copyright==
|
||||
|
||||
This document is licensed under the 2-clause BSD license.
|
||||
|
||||
==Motivation==
|
||||
|
||||
The Taproot Asset protocol is an overlay protocol that enables the
|
||||
representation and transfer of assets on the base Bitcoin blockchain.
|
||||
As Bitcoin is a UTXO-based system each asset is itself rooted at an initial
|
||||
"genesis" transaction, which marks the creation of said asset.
|
||||
An asset is therefore defined by its genesis output, as this marks its lineage.
|
||||
To ensure implementations are able to verify provenance proofs across the
|
||||
ecosystem, a standardized proof format is proposed. The proof format is a linear
|
||||
log of state transitions, allowing new transfers/transition to simply be append
|
||||
to the end of the fail.
|
||||
|
||||
==Design==
|
||||
|
||||
Proving provenance of an asset requires the following arguments at each point
|
||||
in the past history of the asset:
|
||||
* The very first snapshot of an asset is rooted at the genesis outpoint as dictated by the canonical Universe.
|
||||
* A valid merkle proof that proves the inclusion of the genesis outpoint and resulting created asset.
|
||||
* At each step/transition beyond the genesis outpoint:
|
||||
** A valid merkle proof of a transaction which spends the outpoint referenced in the prior step.
|
||||
** A valid MS-SMT opening proving the commitment of the new location of the asset.
|
||||
** A valid asset witness state transition from the prior outpoint to the new location.
|
||||
** A valid canonical Taproot Asset commitment exists for the given asset.
|
||||
** If the transaction anchoring the state transition has other Taproot (P2TR) outputs, then a valid tapscript exclusion proof to prove that the commitment isn't duplicated elsewhere.
|
||||
|
||||
===Specification===
|
||||
|
||||
The Taproot Asset proof file is a flat file that records each relevant state
|
||||
transition for a given asset to be verified. The file is verified incrementally,
|
||||
with verification halting if an invalid state transition or proof is
|
||||
encountered.
|
||||
|
||||
A file is a series of inclusion and state transition proofs rooted at a given
|
||||
genesis outpoint. The very first transition requires no witness validation as
|
||||
its the genesis outpoint.
|
||||
|
||||
====File Serialization====
|
||||
|
||||
A single inclusion and state transition proof has the following format is a TLV
|
||||
blob with the following format:
|
||||
* type: 0 (<code>version</code>)
|
||||
** value:
|
||||
*** [<code>uint32</code>:<code>version</code>]
|
||||
* type: 1 (<code>prev_out</code>)
|
||||
** value:
|
||||
*** [<code>36*byte</code>:<code>txid || output_index</code>]
|
||||
* type: 2 (<code>block_header</code>)
|
||||
** value:
|
||||
*** [<code>80*byte</code>:<code>bitcoin_header</code>]
|
||||
* type: 3 (<code>anchor_tx</code>)
|
||||
** value:
|
||||
*** [<code>...*byte</code>:<code>serialized_bitcoin_tx</code>]
|
||||
* type: 4 (<code>anchor_tx_merkle_proof</code>)
|
||||
** value:
|
||||
*** [<code>...*byte</code>:<code>merkle_inclusion_proof</code>]
|
||||
* type: 5 (<code>taproot_asset_asset_leaf</code>)
|
||||
** value:
|
||||
*** [<code>tlv_blob</code>:<code>serialized_tlv_leaf</code>]
|
||||
* type: 6 (<code>taproot_asset_inclusion_proofs</code>)
|
||||
** value:
|
||||
*** [<code>...*byte</code>:<code>taproot_asset_taproot_proof</code>]
|
||||
**** type: 0 (<code>output_index</code>
|
||||
***** value: [<code>int32</code>:<code>index</code>]
|
||||
**** type: 1 (<code>internal_key</code>
|
||||
***** value: [<code>33*byte</code>:<code>y_parity_byte || schnorr_x_only_key</code>]
|
||||
**** type: 2 (<code>taproot_asset_proof</code>)
|
||||
***** value: [<code>...*byte</code>:<code>asset_proof</code>]
|
||||
****** type: 0 (<code>taproot_asset_proof</code>)
|
||||
******* value: [<code>...*byte</code>:<code>asset_inclusion_proof</code>]
|
||||
******* type: 0
|
||||
******** value: [<code>uint32</code>:<code>proof_version</code>]
|
||||
******* type: 1
|
||||
******** value: [<code>32*byte</code>:<code>asset_id</code>]
|
||||
******* type: 2
|
||||
******** value: [<code>...*byte</code>:<code>ms_smt_inclusion_proof</code>]
|
||||
****** type: 1 (<code>taproot_asset_inclusion_proof</code>)
|
||||
******* value: [<code>...*byte</code>:<code>taproot_asset_inclusion_proof</code>]
|
||||
******* type: 0
|
||||
******** value: [<code>uint32</code>:<code>proof_version</code>]
|
||||
******* type: 1
|
||||
******** value: [<code>...*byte</code>:<code>ms_smt_inclusion_proof</code>]
|
||||
******* type: 2 (<code>taproot_sibling_preimage</code>)
|
||||
******** value: [<code>byte</code>:<code>sibling_type</code>][<code>varint</code>:<code>num_bytes</code>][<code>...*byte</code>:<code>tapscript_preimage</code>]
|
||||
**** type: 3 (<code>taproot_asset_commitment_exclusion_proof</code>
|
||||
***** value: [<code>...*byte</code>:<code>taproot_exclusion_proof</code>]
|
||||
****** type: 0 (<code>tap_image_1</code>)
|
||||
******* value: [<code>...*byte</code>:<code>tapscript_preimage</code>]
|
||||
****** type: 1 (<code>tap_image_2</code>)
|
||||
******* value: [<code>...*byte</code>:<code>tapscript_preimage</code>]
|
||||
****** type: 2 (<code>bip_86</code>)
|
||||
******* value: [<code>byte 0x00/0x01</code>:<code>bip_86</code>]
|
||||
* type: 7 (<code>taproot_exclusion_proofs</code>)
|
||||
** value:
|
||||
*** [<code>uint16</code>:<code>num_proofs</code>][<code>...*byte</code>:<code>taproot_asset_taproot_proof</code>]
|
||||
* type: 8 (<code>split_root_proof</code>)
|
||||
** value:
|
||||
*** [<code>...*byte</code>:<code>taproot_asset_taproot_proof</code>]
|
||||
* type: 9 (<code>meta_reveal</code>)
|
||||
** value:
|
||||
*** [<code>...*byte</code>:<code>asset_meta_reveal</code>]
|
||||
**** type: 0 (<code>meta_type</code>
|
||||
***** value: [<code>uint8</code>:<code>type</code>]
|
||||
**** type: 1 (<code>meta_data</code>
|
||||
***** value: [<code>*byte</code>:<code>meta_data_bytes</code>]
|
||||
* type: 10 (<code>taproot_asset_input_splits</code>)
|
||||
** value:
|
||||
*** [<code>...*byte</code>:<code>nested_proof_map</code>]
|
||||
* type: 11 (<code>challenge_witness</code>)
|
||||
** value:
|
||||
*** [<code>...*byte</code>:<code>challenge_witness</code>]
|
||||
* type: 12 (<code>block_height</code>)
|
||||
** value:
|
||||
*** [<code>uint32</code>:<code>block_height</code>]
|
||||
|
||||
where:
|
||||
* <code>version</code>: is the version of the single mint or transition proof, currently fixed to value <code>0</code>.
|
||||
* <code>prev_out</code>: is the 36-byte outpoint of the Taproot Asset committed output being spent. If this is the very first proof, then this value will be the "genesis outpoint" for the given asset.
|
||||
* <code>block_header</code>: is the 80-byte block header that includes a spend of the above outpoint.
|
||||
* <code>merkle_inclusion_proof</code>: is the merkle inclusion proof of the transaction spending the <code>previous_outpoint</code>. This is serialized with a <code>BigSize</code> length prefix as:
|
||||
** <code>proof_node_count || serialized_proof || proof_direction_bits</code>
|
||||
** where:
|
||||
*** <code>proof_node_count</code> is a <code>BigSize</code> integer specifying the number of nodes in the proof.
|
||||
*** <code>serialized_proof</code> is <code>proof_node_count*32</code> bytes for the proof path.
|
||||
*** <code>proof_direction_bits</code> is a bitfield of size <code>length_of_proof</code> with a value of <code>0</code> indicating a left direction, and <code>1</code> indicating a right direction.
|
||||
* <code>anchor_tx</code>: is the transaction spending the <code>previous_outpoint</code>. This transaction commits to at least a single Taproot Asset tree within one of its outputs.
|
||||
* <code>taproot_asset_taproot_proof</code>: is a nested TLV that can be used to prove either inclusion or a Taproot Asset, or the lack of a Taproot Asset commitment via the <code>taproot_asset_commitment_exclusion_proof</code>.
|
||||
* <code>taproot_exclusion_proofs</code>: is a series of _exclusion_ proofs that prove that the other outputs in a transaction don't commit to a valid Taproot Asset. This re-uses the <code>taproot_asset_taproot_proof</code> structure, but will only contain an <code>taproot_asset_commitment_exclusion_proof</code> value and not also a <code>taproot_asset_taproot_proof</code> value.
|
||||
* <code>split_root_proof</code>: is an optional <code>taproot_asset_taproot_proof</code> that proves the inclusion of the split commitment's root asset in case of an asset split.
|
||||
* <code>taproot_asset_input_splits</code>: is an optional list of nested full proofs for any additional inputs found within the resulting asset.
|
||||
* <code>asset_meta_reveal</code>: is an mandatory field (for genesis assets) that reveals the pre-image of the <code>asset_meta_hash</code> contained in the asset TLV.
|
||||
** The <code>meta_type</code> field can be used to indicate how to parse/render the meta data pre-image.
|
||||
*** The meta type currently defined are:
|
||||
**** <code>0</code>: no true type, just designates an opaque data blob.
|
||||
** The <code>meta_data</code> is the raw meta data itself.
|
||||
*** If the contained asset is a genesis asset (has a valid genesis witness), then a verifier SHOULD verify that: `sha256(tlv_encode(meta_reveal)) == asset_meta_hash`.
|
||||
*** This field MUST only be present for genesis asset proofs.
|
||||
* <code>challenge_witness</code> is an optional asset witness over a well-defined asset state transition that proves ownership of the <code>script_key</code> the asset currently resides at.
|
||||
* <code>block_height</code>: is the block height of the block that includes a spend of the <code>prev_out</code> outpoint.
|
||||
|
||||
The final flat proof file has the following format:
|
||||
* [<code>u32</code>:<code>file_version</code>] version of proof file format, currently fixed to <code>0</code>.
|
||||
* [<code>BigSize</code>:<code>num_proofs</code>] number of proofs contained in the file
|
||||
* [<code>num_proof*proof</code>:<code>proofs</code>] encoded proofs
|
||||
** [<code>BigSize</code>:<code>proof_len</code>] length of encoded proof
|
||||
** [<code>proof_len*byte</code>:<code>proof_tlv_bytes</code>] a single proof encoded as a TLV stream as defined above
|
||||
** [<code>32*byte</code>:<code>proof_checksum</code>] the checksum of the proof, which is <code>SHA256(prev_hash || proof_tlv_bytes)</code> where <code>prev_hash</code> is the checksum of the previous proof or a zero hash for the first proof.
|
||||
|
||||
====Proof Verification====
|
||||
|
||||
Verification of a proof file starts at the first entry (the genesis output
|
||||
creation) and walks forward, validating each state transition and inclusion
|
||||
proof in series. If any state transition is found to be invalid, then the asset
|
||||
proof is invalid. Otherwise, if the file is consumed in full without any
|
||||
violations, the proof is said to be valid.
|
||||
|
||||
Given a proof file for a given asset <code>f_proof</code>, genesis outpoint
|
||||
<code>g</code> verification is defined as follows:
|
||||
# Verify the integrity of the proof file:
|
||||
## For each proof, extract the <code>proof_len</code>, <code>proof_len</code> number of bytes as <code>proof_tlv_bytes</code> and 32 bytes <code>proof_checksum</code>.
|
||||
## Compute <code>SHA256(prev_hash || proof_tlv_bytes)</code> where <code>prev_hash</code> is the <code>proof_checksum</code> of the previous proof or a 32-byte zero hash for the first proof in a file.
|
||||
## If this computed value doesn't match <code>proof_checksum</code>, verification fails.
|
||||
# Verify each inclusion proof and state transition:
|
||||
## Parse the next proof block from the flat file.
|
||||
## If this is the first proof to be verified:
|
||||
### Store the <code>previous_outpoint</code> as the genesis outpoint.
|
||||
## Otherwise, verify that the <code>anchor_transaction</code> has an inputs that spends the ''prior'' <code>previous_outpoint</code>
|
||||
## Given the <code>anchor_transaction</code> verify that the included <code>merkle_inclusion_proof</code> rooted at the merkle root of the <code>block_header</code> is valid.
|
||||
## Parse the <code>tlv_proof_map</code>.
|
||||
## If the <code>anchor_transaction</code> does not have ''at least'' <code>asset_output_pos</code> outputs, verification fails.
|
||||
## Verify that the <code>asset_leaf_proof</code> embeds the <code>taproot_asset_leaf</code> at the outpout rooted at the <code>asset_output_pos</code> using the specified <code>internal_key</code> to compute the taproot commitment.
|
||||
## Verify that the asset witness included at the <code>prev_asset_witness</code> field of the <code>taproot_asset_leaf</code> is valid based on the specific <code>asset_script_version</code>
|
||||
## If a <code>split_commitment_opening</code> is present, verify that the included leaf is a valid opening rooted at the <code>taproot_asset_leaf</code>'s <code>split_commitment_root</code> field.
|
||||
## If a <code>split_commitment_opening</code> is present, verify that an inclusion proof for the <code>split_commitment_root</code>'s leaf is present in <code>split_root_proof</code>.
|
||||
## If the asset is a genesis asset, and the <code>asset_meta</code> field is present, then verify that <code>sha256(asset_meta) == asset.asset_meta_hash</code>
|
||||
|
||||
A pseudo-code routine for flat file verification follows:
|
||||
<source lang="python">
|
||||
verify_asset_file_proof(file_proof []byte, genesis_outpoint OutPoint,
|
||||
assetID [32]byte) -> bool
|
||||
|
||||
genesis_outpoint, prev_outpoint = None
|
||||
file_reader = new_bytes_reader(file_proof)
|
||||
prev_hash = bytes(32)
|
||||
while file_reader.len() != 0:
|
||||
proof_block = parse_proof_block(file_reader)
|
||||
|
||||
sha_sum = sh256(prev_hash + proof_block.bytes())
|
||||
if proof_block.proof_checksum != sha_sum:
|
||||
return false
|
||||
|
||||
if genesis_outpoint is None:
|
||||
genesis_outpoint = proof_block.previous_outpoint
|
||||
|
||||
txn = proof_block.txn
|
||||
if genesis_outpoint is not None:
|
||||
if !spends_prev_out(txn):
|
||||
return false
|
||||
|
||||
if !verify_merkle_proof(
|
||||
proof_block.block_header, proof_block.merkle_inclusion_proof, txn,
|
||||
):
|
||||
return false
|
||||
|
||||
proof_tlv_map = proof_block.tlv_map
|
||||
|
||||
if len(txn.outputs) < proof_tlv_map.asset_output_pos:
|
||||
return false
|
||||
|
||||
if !verify_asset_tree_proof(
|
||||
txn, proof_tlv_map.taproot_asset_leaf, proof_tlv_map.asset_leaf_proof,
|
||||
):
|
||||
return false
|
||||
|
||||
if !verify_taproot_asset_state_transition(proof_tlv_map.taproot_asset_leaf):
|
||||
return false
|
||||
|
||||
if proof_tlv_map.challenge_witness is not None:
|
||||
new_leaf = clone_unique_leaf(proof_tlv_map.taproot_asset_leaf)
|
||||
new_leaf.script_key = NUMS_key
|
||||
new_leaf.prev_witnesses = {{
|
||||
prev_id: {
|
||||
asset_id: proof_tlv_map.taproot_asset_leaf.asset_id
|
||||
outpoint: 00000000...0000000:0
|
||||
script_key: proof_tlv_map.taproot_asset_leaf.script_key
|
||||
}
|
||||
tx_witness: proof_tlv_map.challenge_witness
|
||||
}}
|
||||
|
||||
if !verify_taproot_asset_state_transition(new_leaf):
|
||||
return false
|
||||
|
||||
if proof_tlv_map.split_commitment_opening is not None:
|
||||
if !verify_split_commitment(
|
||||
proof_tlv_map.taproot_asset_leaf,
|
||||
proof_tlv_map.split_commitment_opening,
|
||||
):
|
||||
return false
|
||||
|
||||
if !verify_asset_tree_proof(
|
||||
txn,
|
||||
proof_tlv_map.split_commitment_opening.split_commitment_root,
|
||||
proof_tlv_map.split_root_proof,
|
||||
):
|
||||
return false
|
||||
|
||||
has_meta_reveal = proof_tlv_map.meta_reveal is not None
|
||||
has_meta_hash = proof_tlv_map.asset.meta_hash is not None
|
||||
is_genesis_asset = is_genesis_asset(proof_tlv_map.asset)
|
||||
match:
|
||||
case has_meta_reveal && !is_genesis_asset:
|
||||
return false
|
||||
|
||||
case has_meta_reveal && is_genesis_asset:
|
||||
meta_hash := sha256(meta_reveal)
|
||||
if meta_hash != proof_tlv_map.asset.meta_hash:
|
||||
return false
|
||||
|
||||
case has_meta_hash && is_genesis_asset && !has_meta_reveal:
|
||||
return false
|
||||
|
||||
case !has_meta_reveal && is_genesis_asset:
|
||||
return false
|
||||
|
||||
return true
|
||||
</source>
|
||||
|
||||
=====Ownership proof=====
|
||||
|
||||
An optional ownership proof can be added to a proof through the
|
||||
<code>challenge_witness</code> field. That witness must be a valid asset
|
||||
<code>tx_witness</code> over a well-defined asset state transition that spends
|
||||
the full amount of the asset to the NUMS key.
|
||||
The state transition can be created with the following steps:
|
||||
|
||||
# Create a deep copy of the asset to prove ownership of.
|
||||
# Truncate the <code>prev_witnesses</code> list to just a single element.
|
||||
# Set the <code>prev_witnesses[0].prev_id.out_point</code> to the empty outpoint (all zero hash and zero index).
|
||||
# Set the <code>prev_witnesses[0].prev_id.script_key</code> to the asset's script key.
|
||||
# Set the asset's <code>script_key</code> to the NUMS key.
|
||||
# Create a signature for the asset state transition, using the interactive flow (no split tomb stone).
|
||||
# Extract just the <code>prev_witnesses[0].tx_witness</code> from the signed state transition and append that to the proof as the <code>challenge_witness</code>.
|
||||
|
||||
==Test Vectors==
|
||||
|
||||
Test vectors for the [[File Serialization]] can be found here:
|
||||
* [[bip-tap-proof-file/proof_tlv_encoding_generated.json|Proof TLV encoding test vectors]]
|
||||
* [[bip-tap-proof-file/proof_tlv_encoding_error_cases.json|Proof TLV encoding error test vectors]]
|
||||
* [[bip-tap-proof-file/proof_tlv_encoding_regtest.json|Fully valid regtest proof TLV encoding test vectors]]
|
||||
|
||||
Some of the test vectors are automatically generated by
|
||||
[https://github.com/lightninglabs/taproot-assets/tree/main/proof unit tests in
|
||||
the Taproot Assets GitHub repository].
|
||||
|
||||
==Backwards Compatibility==
|
||||
|
||||
==Reference Implementation==
|
||||
|
||||
github.com/lightninglabs/taproot-assets/tree/main/proof
|
3
bip-tap-proof-file/proof_tlv_encoding_error_cases.json
Normal file
3
bip-tap-proof-file/proof_tlv_encoding_error_cases.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"error_test_cases": null
|
||||
}
|
603
bip-tap-proof-file/proof_tlv_encoding_generated.json
Normal file
603
bip-tap-proof-file/proof_tlv_encoding_generated.json
Normal file
|
@ -0,0 +1,603 @@
|
|||
{
|
||||
"valid_test_cases": [
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"block_header": {
|
||||
"version": 0,
|
||||
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
|
||||
"merkle_root": "f573ed549022595804d8f1151569af45124301c7dc7c8fdf2435b51834176322",
|
||||
"timestamp": 1473417797,
|
||||
"bits": 0,
|
||||
"nonce": 0
|
||||
},
|
||||
"block_height": 1,
|
||||
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120e8bee22dd320d51864e8499a73d374739a0fce94b3eb10c5624ba2159a1c4cdb00000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [],
|
||||
"bits": []
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "8d73ec3f2525632186845c95d4491d1b3a768b7c4e0b6804951aa42655d9b95f:2092150027",
|
||||
"genesis_tag": "eb9d18a44784045d87f3c67cf22746e995af5a25367951baa2ff6cd471c483f1",
|
||||
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"genesis_output_index": 379326753,
|
||||
"genesis_type": 1,
|
||||
"amount": 1,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "0250fb435f8fc76fc75736ac89956406e882a468e929da69ca596a716ebcfa8516",
|
||||
"group_key": {
|
||||
"group_key": "02f51bdc1380b8021dca065edf24ee521a4d6d5ceba51abb7877df544e93acc319",
|
||||
"group_key_sig": "e19478adf14eba5767df3badbd3c6cfa8593a561acd626cb12cae73f8aad4a0b0d1af7a56ac3085991fb5a1b41d699f0fd63a2bea5bfdcef378e5f37c0e0cb0d"
|
||||
}
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "024a821d5ec008712983929de448b8afb6c24e5a1b97367b9a65b6220d7f083fe3",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "af542dec7585eaac495164faeb9c68ebc8b4d8e571a553d6732006063466b65d"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": null,
|
||||
"split_root_proof": null,
|
||||
"meta_reveal": null,
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000002263173418b53524df8f7cdcc701431245af691515f1d8045859229054ed73f54592d2570000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120e8bee22dd320d51864e8499a73d374739a0fce94b3eb10c5624ba2159a1c4cdb0000000003010004fd018a000100018a5fb9d95526a41a9504680b4e7c8b763a1b1d49d4955c8486216325253fec738d7cb3ad0b40656239643138613434373834303435643837663363363763663232373436653939356166356132353336373935316261613266663663643437316334383366310000000000000000000000000000000000000000000000000000000000000000169c11210102010103010106690167006500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000802000009210250fb435f8fc76fc75736ac89956406e882a468e929da69ca596a716ebcfa85160a6102f51bdc1380b8021dca065edf24ee521a4d6d5ceba51abb7877df544e93acc319e19478adf14eba5767df3badbd3c6cfa8593a561acd626cb12cae73f8aad4a0b0d1af7a56ac3085991fb5a1b41d699f0fd63a2bea5bfdcef378e5f37c0e0cb0d059f0004000000000121024a821d5ec008712983929de448b8afb6c24e5a1b97367b9a65b6220d7f083fe3027400490001000120af542dec7585eaac495164faeb9c68ebc8b4d8e571a553d6732006063466b65d02220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b0400000001",
|
||||
"comment": "collectible genesis"
|
||||
},
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"block_header": {
|
||||
"version": 0,
|
||||
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
|
||||
"merkle_root": "6a45e1c2a5f0bde4001a718be7f637e62e5bdd10e0dc3742356fb57370290393",
|
||||
"timestamp": 424111158,
|
||||
"bits": 0,
|
||||
"nonce": 0
|
||||
},
|
||||
"block_height": 1,
|
||||
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120f6299f81fa3ed727d60250c19885a9e03576c506dd58d4c0f55764670beea68900000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [],
|
||||
"bits": []
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "3f71f8cb984b92f67403049442fd5ad145f49143f7f4a5ee3b22b02936d4ff9b:4165004363",
|
||||
"genesis_tag": "bb358b0c3b525da1786f9fff094279db1944ebd7a19d0f7bbacbe0255aa5b7d4",
|
||||
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"genesis_output_index": 2432798076,
|
||||
"genesis_type": 1,
|
||||
"amount": 1,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02661e637f64d8d63f45a25890073502387b18f3f8aa7fd7704348f35ced5423fa",
|
||||
"group_key": {
|
||||
"group_key": "02475ad4761032ee378dff99a4bf0d1f63636d5f0e4df935ba0f117af249628e8c",
|
||||
"group_key_sig": "cd4f5a65a7900c1096f9c994be4ea60eedc281cfd0d00e9260f2fcf9e5dfbd210c0cec330a3d0bd7ed33cee289eb7513ad53c065ab78ee15cca60388c164e215"
|
||||
}
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "02af086d6428c5621941450bbefec061b5056d8706d659f9eebd7043400a4c0f93",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "af9b4888e4061d2fc1980cc7e3eac3f144dd99602b76a159605147a3180a0393"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": "00c01876a914f6c97547d73156abb300ae059905c4acaadd09dd88"
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": null,
|
||||
"split_root_proof": null,
|
||||
"meta_reveal": null,
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000009303297073b56f354237dce010dd5b2ee637f6e78b711a00e4bdf0a5c2e1456a366c47190000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120f6299f81fa3ed727d60250c19885a9e03576c506dd58d4c0f55764670beea6890000000003010004fd018a000100018a9bffd43629b0223beea5f4f74391f445d15afd4294040374f6924b98cbf8713ff840ec4b4062623335386230633362353235646131373836663966666630393432373964623139343465626437613139643066376262616362653032353561613562376434000000000000000000000000000000000000000000000000000000000000000091018d7c01020101030101066901670065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000092102661e637f64d8d63f45a25890073502387b18f3f8aa7fd7704348f35ced5423fa0a6102475ad4761032ee378dff99a4bf0d1f63636d5f0e4df935ba0f117af249628e8ccd4f5a65a7900c1096f9c994be4ea60eedc281cfd0d00e9260f2fcf9e5dfbd210c0cec330a3d0bd7ed33cee289eb7513ad53c065ab78ee15cca60388c164e21505bc000400000000012102af086d6428c5621941450bbefec061b5056d8706d659f9eebd7043400a4c0f93029100490001000120af9b4888e4061d2fc1980cc7e3eac3f144dd99602b76a159605147a3180a039302220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff021b00c01876a914f6c97547d73156abb300ae059905c4acaadd09dd880b0400000001",
|
||||
"comment": "collectible with leaf preimage"
|
||||
},
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"block_header": {
|
||||
"version": 0,
|
||||
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
|
||||
"merkle_root": "90c284d06f3a4d9e08ec96d7f8702e31d4953a8d65171227abac030a78a93bed",
|
||||
"timestamp": 2783629501,
|
||||
"bits": 0,
|
||||
"nonce": 0
|
||||
},
|
||||
"block_height": 1,
|
||||
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120c67a67da813c602d8824a449b2f404c0f35b255bc874852918a3fe072a16a0a300000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [],
|
||||
"bits": []
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "e81ede4561ad67830356aa6b86dff7ab244fcd36e9f7676678e7aa73fac82541:3738690577",
|
||||
"genesis_tag": "c6077dbb5722f5717a289a266f97647981998ebea89c0b4b373970115e82ed6f",
|
||||
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"genesis_output_index": 1050259624,
|
||||
"genesis_type": 1,
|
||||
"amount": 1,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02bc9c371fa4e83557a1844db0a9e636dea420ebc1620a9b6cd499557bb20f5b3e",
|
||||
"group_key": {
|
||||
"group_key": "032964eeba96725a8373fa55867fe0a6d01994d9c8822d8a76ac00181b65b1dd9a",
|
||||
"group_key_sig": "4d07c09a05b7de04956f4f175f3fa6b35249f15619b4a5b4d14b812b7dd1d5e6b0684779937a9762de3f7e30cc95ebdc044d930741dba74b31d3ddc64cef98b8"
|
||||
}
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "021af16655f63c4b9f95b5961ad1c97ef0e8fa7f9218801870e5b2252a6427db8d",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "9d6d650760287dd9a16d719df2303da025dfb675f02a3c5ea525664831646214"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": "016c2e4bb01e316abaaee288d69c06cc608cedefd6e1a06813786c4ec51b6e1d3868ba2662554025b18af167c2ab17cd720b0c46ac7bd5750800b93c0b26a4af43"
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": null,
|
||||
"split_root_proof": null,
|
||||
"meta_reveal": null,
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000ed3ba9780a03acab271217658d3a95d4312e70f8d796ec089e4d3a6fd084c290bdd0eaa50000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120c67a67da813c602d8824a449b2f404c0f35b255bc874852918a3fe072a16a0a30000000003010004fd018a000100018a4125c8fa73aae7786667f7e936cd4f24abf7df866baa56038367ad6145de1ee8ded7e411406336303737646262353732326635373137613238396132363666393736343739383139393865626561383963306234623337333937303131356538326564366600000000000000000000000000000000000000000000000000000000000000003e99b0a801020101030101066901670065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000092102bc9c371fa4e83557a1844db0a9e636dea420ebc1620a9b6cd499557bb20f5b3e0a61032964eeba96725a8373fa55867fe0a6d01994d9c8822d8a76ac00181b65b1dd9a4d07c09a05b7de04956f4f175f3fa6b35249f15619b4a5b4d14b812b7dd1d5e6b0684779937a9762de3f7e30cc95ebdc044d930741dba74b31d3ddc64cef98b805e20004000000000121021af16655f63c4b9f95b5961ad1c97ef0e8fa7f9218801870e5b2252a6427db8d02b7004900010001209d6d650760287dd9a16d719df2303da025dfb675f02a3c5ea52566483164621402220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0241016c2e4bb01e316abaaee288d69c06cc608cedefd6e1a06813786c4ec51b6e1d3868ba2662554025b18af167c2ab17cd720b0c46ac7bd5750800b93c0b26a4af430b0400000001",
|
||||
"comment": "collectible with branch preimage"
|
||||
},
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"block_header": {
|
||||
"version": 0,
|
||||
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
|
||||
"merkle_root": "b1b29433dad76a64f5c3c15f01b6eed67e1511ac310f892662ccea236a5075c0",
|
||||
"timestamp": 3929885861,
|
||||
"bits": 0,
|
||||
"nonce": 0
|
||||
},
|
||||
"block_height": 1,
|
||||
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120fa90a787c9b095646058b3b6c1bdc44753309c94ea8fe446fedca3cbe891e78800000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [],
|
||||
"bits": []
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "2db92d0169a39144afd37941439089bed31f1cb9e6c6a03cb44af864ba29ee07:737360203",
|
||||
"genesis_tag": "a665f606f6a63b7f3dfd2567c18979e4d60f26686d9bf2fb26c901ff354cde16",
|
||||
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"genesis_output_index": 1108760575,
|
||||
"genesis_type": 0,
|
||||
"amount": 5000,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02610f4ad4f6fcb2f75b10b9674cfc140dd97921b53a2f5db4b7f807a5a87d2187",
|
||||
"group_key": {
|
||||
"group_key": "02f2a1617673e0d62a2dfe09f6a7faa670f170256288cfabe4ff98dd993f988a5e",
|
||||
"group_key_sig": "fa3c720b7dc7483f4a33023407490387f752b117f9d9fec5fdb76cfcadcc2ce5ce98d093b6d5e474835cd8191461ce7b6472c5a38ce6c041a6e8676b585894f5"
|
||||
}
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "02f7fd86c602d2ac12d72a7ee0422749b1bfe555c0ee8f24f5ea885a39e36f8cf9",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "a0319d51ea16813396aed95d9a89abbd4478d3ce39b41ac0c1a086dfe89c5fef"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": null,
|
||||
"split_root_proof": null,
|
||||
"meta_reveal": null,
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000c075506a23eacc6226890f31ac11157ed6eeb6015fc1c3f5646ad7da3394b2b1a54c3dea0000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120fa90a787c9b095646058b3b6c1bdc44753309c94ea8fe446fedca3cbe891e7880000000003010004fd018c000100018a07ee29ba64f84ab43ca0c6e6b91c1fd3be8990434179d3af4491a369012db92d2bf3394b40613636356636303666366136336237663364666432353637633138393739653464363066323636383664396266326662323663393031666633353463646531360000000000000000000000000000000000000000000000000000000000000000421657ff000201000303fd1388066901670065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000092102610f4ad4f6fcb2f75b10b9674cfc140dd97921b53a2f5db4b7f807a5a87d21870a6102f2a1617673e0d62a2dfe09f6a7faa670f170256288cfabe4ff98dd993f988a5efa3c720b7dc7483f4a33023407490387f752b117f9d9fec5fdb76cfcadcc2ce5ce98d093b6d5e474835cd8191461ce7b6472c5a38ce6c041a6e8676b585894f5059f000400000000012102f7fd86c602d2ac12d72a7ee0422749b1bfe555c0ee8f24f5ea885a39e36f8cf9027400490001000120a0319d51ea16813396aed95d9a89abbd4478d3ce39b41ac0c1a086dfe89c5fef02220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b0400000001",
|
||||
"comment": "normal genesis"
|
||||
},
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"block_header": {
|
||||
"version": 0,
|
||||
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
|
||||
"merkle_root": "dfe3487fad14f5dacca8e1a1f5652210df638b0639d252228491be1c1a700f65",
|
||||
"timestamp": 1729403804,
|
||||
"bits": 0,
|
||||
"nonce": 0
|
||||
},
|
||||
"block_height": 1,
|
||||
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120bca2d7e7dd677df0ce9b9c1cea124c674ead284bf60dadd8ed967d47685d396e00000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [],
|
||||
"bits": []
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "41e52ad269fd8e5f04756b36dbc9b344e9031d27b8b352f7ab3641fe3dea7902:2817351063",
|
||||
"genesis_tag": "17e924aef78ae151c00755925836b7075885650c30ec29a3703934bf50a28da1",
|
||||
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"genesis_output_index": 647263805,
|
||||
"genesis_type": 0,
|
||||
"amount": 5000,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "029e47e906bfa2ee6cbba2c920b6f80d679928c40fe0c147d33c68cc5543f14637",
|
||||
"group_key": {
|
||||
"group_key": "030785de067c85d0cd3d27a4fdebe7394c1d18520a4303a415d3ba00f9429b2ef3",
|
||||
"group_key_sig": "4f70f482651e959550cc897a94dea65d7ffacfa6d0842fa4de9b5bf9b5fee60e0ac3cdc60a9a22627af9c3ee6d6397eaced206bf3f6473f623b6ea44bbc96206"
|
||||
}
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "02f820ac404967c0e36fcd7a0d6d8e8a3150801f18947c2299a2e024bf8aa25341",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "7440c1f12cf25120108c1b827e62ccfcde709a664cb3fb8396ab70aa18546f8a"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": "00c01876a914f6c97547d73156abb300ae059905c4acaadd09dd88"
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": null,
|
||||
"split_root_proof": null,
|
||||
"meta_reveal": null,
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000650f701a1cbe91842252d239068b63df102265f5a1e1a8ccdaf514ad7f48e3df9c9b14670000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a01000000000000225120bca2d7e7dd677df0ce9b9c1cea124c674ead284bf60dadd8ed967d47685d396e0000000003010004fd018c000100018a0279ea3dfe4136abf752b3b8271d03e944b3c9db366b75045f8efd69d22ae541a7ed5d97403137653932346165663738616531353163303037353539323538333662373037353838353635306333306563323961333730333933346266353061323864613100000000000000000000000000000000000000000000000000000000000000002694763d000201000303fd13880669016700650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080200000921029e47e906bfa2ee6cbba2c920b6f80d679928c40fe0c147d33c68cc5543f146370a61030785de067c85d0cd3d27a4fdebe7394c1d18520a4303a415d3ba00f9429b2ef34f70f482651e959550cc897a94dea65d7ffacfa6d0842fa4de9b5bf9b5fee60e0ac3cdc60a9a22627af9c3ee6d6397eaced206bf3f6473f623b6ea44bbc9620605bc000400000000012102f820ac404967c0e36fcd7a0d6d8e8a3150801f18947c2299a2e024bf8aa253410291004900010001207440c1f12cf25120108c1b827e62ccfcde709a664cb3fb8396ab70aa18546f8a02220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff021b00c01876a914f6c97547d73156abb300ae059905c4acaadd09dd880b0400000001",
|
||||
"comment": "normal with leaf preimage"
|
||||
},
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"block_header": {
|
||||
"version": 0,
|
||||
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
|
||||
"merkle_root": "cff9e231e7cffb62784ce3cfb8def691c3d7529fe94205f6e32baf8466e9e616",
|
||||
"timestamp": 1018572551,
|
||||
"bits": 0,
|
||||
"nonce": 0
|
||||
},
|
||||
"block_height": 1,
|
||||
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a010000000000002251208f18ebe5a34e6fd58693a21a3b7357b25f17f16ce85f1ce4ef48981bb4d73f9b00000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [],
|
||||
"bits": []
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "d6090ec04ff5f26283efc6c6443faf8eb3e4a15ca80d72521a90ae3e3e4a3056:210616852",
|
||||
"genesis_tag": "01a239c4365854c3af7f6b41d631f92b9a8d12f41257325fff332f7576b06205",
|
||||
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"genesis_output_index": 3243509860,
|
||||
"genesis_type": 0,
|
||||
"amount": 5000,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02ca32de61e7923279664dc4d609b8e68cd88fcd096bcfc5fcbd9d5e20ed14f455",
|
||||
"group_key": {
|
||||
"group_key": "03f072d865cd42fbd6290c62c0a7067a403c9557fb998bd9736ceea5a774b974af",
|
||||
"group_key_sig": "1924b5e819e5e26eed905d14d39898aed2d9dcab3f91d80a94a272756164ae634177042d85c8a7593613771ce1d981a8d88af6b209c77daefb6e0fbac0137377"
|
||||
}
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "02210ce45fef3bc702f0878323249c0263e0288217f9374a3661ec361d5261474f",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "f15e3049ab9c051ddf9d5e5cba119339708418231d3ce06789174e4e3c682271"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": "016c2e4bb01e316abaaee288d69c06cc608cedefd6e1a06813786c4ec51b6e1d3868ba2662554025b18af167c2ab17cd720b0c46ac7bd5750800b93c0b26a4af43"
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": null,
|
||||
"split_root_proof": null,
|
||||
"meta_reveal": null,
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000000016e6e96684af2be3f60542e99f52d7c391f6deb8cfe34c7862fbcfe731e2f9cf072fb63c0000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a010000000000002251208f18ebe5a34e6fd58693a21a3b7357b25f17f16ce85f1ce4ef48981bb4d73f9b0000000003010004fd018c000100018a56304a3e3eae901a52720da85ca1e4b38eaf3f44c6c6ef8362f2f54fc00e09d60c8dc21440303161323339633433363538353463336166376636623431643633316639326239613864313266343132353733323566666633333266373537366230363230350000000000000000000000000000000000000000000000000000000000000000c1540864000201000303fd1388066901670065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000092102ca32de61e7923279664dc4d609b8e68cd88fcd096bcfc5fcbd9d5e20ed14f4550a6103f072d865cd42fbd6290c62c0a7067a403c9557fb998bd9736ceea5a774b974af1924b5e819e5e26eed905d14d39898aed2d9dcab3f91d80a94a272756164ae634177042d85c8a7593613771ce1d981a8d88af6b209c77daefb6e0fbac013737705e2000400000000012102210ce45fef3bc702f0878323249c0263e0288217f9374a3661ec361d5261474f02b700490001000120f15e3049ab9c051ddf9d5e5cba119339708418231d3ce06789174e4e3c68227102220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0241016c2e4bb01e316abaaee288d69c06cc608cedefd6e1a06813786c4ec51b6e1d3868ba2662554025b18af167c2ab17cd720b0c46ac7bd5750800b93c0b26a4af430b0400000001",
|
||||
"comment": "normal with branch preimage"
|
||||
},
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"block_header": {
|
||||
"version": 0,
|
||||
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
|
||||
"merkle_root": "50407cde9e5f0cf21ae351f4997d3cc3122f9a93e3c3a16f5269c619ec1211c3",
|
||||
"timestamp": 3691164560,
|
||||
"bits": 0,
|
||||
"nonce": 0
|
||||
},
|
||||
"block_height": 1,
|
||||
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a010000000000002251200874649b4e0e0f15fd5e47d337a19eead0e4ad7fd2ec8a6bdbd5c20d6c60329600000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [],
|
||||
"bits": []
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "70e7ac7417bf383423cfcde2c269398e40b01aa47d7fbfbcafd915bb5ce263e2:1058894887",
|
||||
"genesis_tag": "6710a7960732ca52cf53c3f520c889b79bf504cfb57c7601232d589baccea9d6",
|
||||
"genesis_meta_hash": "a34a4bd8a261e96320dcd1e43f134b84f3421a5433336724de1aa5d07cef6d13",
|
||||
"genesis_output_index": 503926682,
|
||||
"genesis_type": 0,
|
||||
"amount": 5000,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "024236a05cff1fc479f8a2abc0fb95874b4e416bb9f4e617e85a8ea8b492189a56",
|
||||
"group_key": {
|
||||
"group_key": "02b6f3ea9dbc2aec162b5c5461fde8e000e8ce33e75e71e9053edb4564dea457cd",
|
||||
"group_key_sig": "ddb89159dd50a9ca6794aec56895a26e7b4b9c92e1d96158cc49de9d87051adc904de5b3ddbe9c2f5f959cf142b2b3c5ef92f73269a062de75b8d6bf0b4b7309"
|
||||
}
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "02a1581b958162db9a2ab8b13079694ab91ea08ba74e99635af948e7141dcdcdfe",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "3e3ac273be361ad0f51e35fe02af232e01de9043d7d701594387c556877ac537"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": null,
|
||||
"split_root_proof": null,
|
||||
"meta_reveal": {
|
||||
"type": 0,
|
||||
"data": "6d65616e7420696e2063726f6b696e67206e657665726d6f7265"
|
||||
},
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000c31112ec19c669526fa1c3e3939a2f12c33c7d99f451e31af20c5f9ede7c405090b302dc0000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a010000000000002251200874649b4e0e0f15fd5e47d337a19eead0e4ad7fd2ec8a6bdbd5c20d6c6032960000000003010004fd018c000100018ae263e25cbb15d9afbcbf7f7da41ab0408e3969c2e2cdcf233438bf1774ace7703f1d74274036373130613739363037333263613532636635336333663532306338383962373962663530346366623537633736303132333264353839626163636561396436a34a4bd8a261e96320dcd1e43f134b84f3421a5433336724de1aa5d07cef6d131e094f9a000201000303fd13880669016700650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080200000921024236a05cff1fc479f8a2abc0fb95874b4e416bb9f4e617e85a8ea8b492189a560a6102b6f3ea9dbc2aec162b5c5461fde8e000e8ce33e75e71e9053edb4564dea457cdddb89159dd50a9ca6794aec56895a26e7b4b9c92e1d96158cc49de9d87051adc904de5b3ddbe9c2f5f959cf142b2b3c5ef92f73269a062de75b8d6bf0b4b7309059f000400000000012102a1581b958162db9a2ab8b13079694ab91ea08ba74e99635af948e7141dcdcdfe0274004900010001203e3ac273be361ad0f51e35fe02af232e01de9043d7d701594387c556877ac53702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff081f000100011a6d65616e7420696e2063726f6b696e67206e657665726d6f72650b0400000001",
|
||||
"comment": "normal asset with a meta reveal"
|
||||
},
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"block_header": {
|
||||
"version": 0,
|
||||
"prev_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
|
||||
"merkle_root": "632d8d2fc327b4d5453769145b341a0b3111872b481a92e303fc6a91680bf45f",
|
||||
"timestamp": 1084726331,
|
||||
"bits": 0,
|
||||
"nonce": 0
|
||||
},
|
||||
"block_height": 1,
|
||||
"anchor_tx": "02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a0100000000000022512094f2a868ad1f3bee9f11e8fa309fba5eb4f9ec4964c4eefa9325b18ca0a3c80d00000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [],
|
||||
"bits": []
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "0cb058bd10f13e41b7c09a3e6f241c576f9ac7070f0914c3f10e0f21255197d7:1325329117",
|
||||
"genesis_tag": "8f8921a266b11d0f334c62fe52ba53af19779cb2948b6570ffa0b773963c130a",
|
||||
"genesis_meta_hash": "691a588e330c10a4ec7261f0b571486a8223f13fd7594e60eee6ce8013bf232f",
|
||||
"genesis_output_index": 4105630847,
|
||||
"genesis_type": 1,
|
||||
"amount": 1,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "020aca705bbfdaea0fdaa052837c3801953a2642ca7009a99fe2884cb616bce3a5",
|
||||
"group_key": {
|
||||
"group_key": "02c59d39e7c47626d9b9153495b5ce750716818a19938d2730692ed8bbafce5f21",
|
||||
"group_key_sig": "52d12e017cd2430e08d272ec76baea5aaac6960c72f5487e683034dfae35ce0d4301c573e13e1fd0d700c3349dc0a93ffb0867be04f862a6dd7962e1eb567628"
|
||||
}
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "0265c2da862edf7e730c69c5f1677ce0104a81adda912cc97f54a7aeec9e1b0943",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "99539548cd53af1920671ef2c07d9078ad6ffd2646563197fecb125a687f9548"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": null,
|
||||
"split_root_proof": null,
|
||||
"meta_reveal": {
|
||||
"type": 0,
|
||||
"data": "7368616c6c206265206c6966746564206e657665726d6f7265"
|
||||
},
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "00240000000000000000000000000000000000000000000000000000000000000000000000000150000000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000005ff40b68916afc03e3921a482b8711310b1a345b14693745d5b427c32f8d2d633b9ca7400000000000000000025e02000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000014a0100000000000022512094f2a868ad1f3bee9f11e8fa309fba5eb4f9ec4964c4eefa9325b18ca0a3c80d0000000003010004fd018a000100018ad7975125210f0ef1c314090f07c79a6f571c246f3e9ac0b7413ef110bd58b00c4efeeadd4038663839323161323636623131643066333334633632666535326261353361663139373739636232393438623635373066666130623737333936336331333061691a588e330c10a4ec7261f0b571486a8223f13fd7594e60eee6ce8013bf232ff4b6f47f010201010301010669016700650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080200000921020aca705bbfdaea0fdaa052837c3801953a2642ca7009a99fe2884cb616bce3a50a6102c59d39e7c47626d9b9153495b5ce750716818a19938d2730692ed8bbafce5f2152d12e017cd2430e08d272ec76baea5aaac6960c72f5487e683034dfae35ce0d4301c573e13e1fd0d700c3349dc0a93ffb0867be04f862a6dd7962e1eb567628059f00040000000001210265c2da862edf7e730c69c5f1677ce0104a81adda912cc97f54a7aeec9e1b094302740049000100012099539548cd53af1920671ef2c07d9078ad6ffd2646563197fecb125a687f954802220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff081e00010001197368616c6c206265206c6966746564206e657665726d6f72650b0400000001",
|
||||
"comment": "collectible with a meta reveal"
|
||||
}
|
||||
],
|
||||
"error_test_cases": null
|
||||
}
|
911
bip-tap-proof-file/proof_tlv_encoding_regtest.json
Normal file
911
bip-tap-proof-file/proof_tlv_encoding_regtest.json
Normal file
|
@ -0,0 +1,911 @@
|
|||
{
|
||||
"valid_test_cases": [
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
|
||||
"block_header": {
|
||||
"version": 541065216,
|
||||
"prev_block": "44d3b42cf499c0e5c7ce75cb2b9d293b161361101620108c873d4e90772221e6",
|
||||
"merkle_root": "e3a640f85a22dcf6082c8279aacae8bcbf58183b50e75efc05a844a88dbcff79",
|
||||
"timestamp": 1693480105,
|
||||
"bits": 545259519,
|
||||
"nonce": 0
|
||||
},
|
||||
"block_height": 441,
|
||||
"anchor_tx": "02000000000101005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a0000000000ffffffff02e803000000000000225120c5532da05265abb1b740828a423046bc2b38fab6f4deb8a13fc64f59be9fc001debcf50500000000225120b061c4c81aed3d158ad8abbeda73fa76389323e53461ae3727894e4ffe582c0e02483045022100a3c7343891257da013708411998c8f685dbe1e77c0a222bf11227d79a29a9a6002205f4330bc32e5f0f8836db23b21c8b640490153e1403bb1a80998960bfbec3a6101210381c26249078b3fb3ad2387ff1ce4d8153dddf7258bc5b58b409fcd16d3df9d5900000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [
|
||||
"18791a381a48962338b8f5b0b882adee702b3b13c8a76127aaca77b169ac08dd"
|
||||
],
|
||||
"bits": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
|
||||
"genesis_tag": "first-itestbuxx",
|
||||
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
|
||||
"genesis_output_index": 0,
|
||||
"genesis_type": 0,
|
||||
"amount": 1500,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e93",
|
||||
"group_key": null
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "02fa4d23d048dbc292f69a5ca081b9f0b3c5cb4886b7f1767428609e375479345d",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "000129606637cd38716268bf1cca64ae036c73d5fa95e1258d56085128a30d2b087f00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": [
|
||||
{
|
||||
"output_index": 1,
|
||||
"internal_key": "024201da6b9645e123229f440ff1007691251a3b8a5d85c8321e28d640d61163da",
|
||||
"commitment_proof": null,
|
||||
"tapscript_proof": {
|
||||
"tap_preimage_1": "",
|
||||
"tap_preimage_2": "",
|
||||
"bip86": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"split_root_proof": null,
|
||||
"meta_reveal": {
|
||||
"type": 0,
|
||||
"data": "69746573742d6d65746164617461"
|
||||
},
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "0024005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a00000000015000004020e6212277904e3d878c102016106113163b299d2bcb75cec7e5c099f42cb4d34479ffbc8da844a805fc5ee7503b1858bfbce8caaa79822c08f6dc225af840a6e3a974f064ffff7f200000000002f702000000000101005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a0000000000ffffffff02e803000000000000225120c5532da05265abb1b740828a423046bc2b38fab6f4deb8a13fc64f59be9fc001debcf50500000000225120b061c4c81aed3d158ad8abbeda73fa76389323e53461ae3727894e4ffe582c0e02483045022100a3c7343891257da013708411998c8f685dbe1e77c0a222bf11227d79a29a9a6002205f4330bc32e5f0f8836db23b21c8b640490153e1403bb1a80998960bfbec3a6101210381c26249078b3fb3ad2387ff1ce4d8153dddf7258bc5b58b409fcd16d3df9d5900000000032201dd08ac69b177caaa2761a7c8133b2b70eead82b8b0f5b8382396481a381a79180004f80001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd05dc066901670065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000092102aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e9305c7000400000000012102fa4d23d048dbc292f69a5ca081b9f0b3c5cb4886b7f1767428609e375479345d029c004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff014f000100014a000129606637cd38716268bf1cca64ae036c73d5fa95e1258d56085128a30d2b087f00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf0630012e0004000000010121024201da6b9645e123229f440ff1007691251a3b8a5d85c8321e28d640d61163da03030201010813000100010e69746573742d6d657461646174610b04000001b9",
|
||||
"comment": "valid regtest genesis proof with meta reveal"
|
||||
},
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "154acf44a7c6c85b04d2adab29ae203a221e42040252f906f5e4da0257d8bb75:0",
|
||||
"block_header": {
|
||||
"version": 0,
|
||||
"prev_block": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"merkle_root": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"timestamp": 2288912640,
|
||||
"bits": 0,
|
||||
"nonce": 0
|
||||
},
|
||||
"block_height": 0,
|
||||
"anchor_tx": "0200000000010206da3d8b7253faa4c9663f2124477d70d9bb93c39792d2e78ce80954144757140000000000ffffffff75bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a1500000000000000000003e8030000000000002251201aa347eeaed967cc1da29ae63e16c6b0d7e653cb8465d9678c03a5aadd469693e8030000000000002251207f80e879022a8ed063078bc89507e1727e167a924c56e82a6ac51ca977149bc94aa9f50500000000225120424ee9a5071750b1ba0b55c9f0f2613fe1e10616bfcb399c661833941daed17902483045022100e73decba204d5f83eeb1a37c6ecedad978291b5dd315fd6aa20c965a35b19fce02207b71da7bb58c371ebe08b758dd79e7f2f303776103bf9e3391389ed2b57f7aab0121035c30c18e240e7fed40d08bea7abf3fe73c79b28503aed33c32c71b5d7866d8a401403331ea969fa7be783b7411582d16fe24db46ea3f5a3da418d3c9fa47be53e4aba69903530d0615628d5abe1f65af45d2513fc07742cc28872f22148f2fa2974900000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [],
|
||||
"bits": []
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
|
||||
"genesis_tag": "first-itestbuxx",
|
||||
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
|
||||
"genesis_output_index": 0,
|
||||
"genesis_type": 0,
|
||||
"amount": 300,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "154acf44a7c6c85b04d2adab29ae203a221e42040252f906f5e4da0257d8bb75:0",
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717",
|
||||
"script_key": "02aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e93"
|
||||
},
|
||||
"tx_witness": [
|
||||
"a78a0f6e328c20913a01cf65573cc0ea7f475e935e4c96e12acfe4071ee40b70694ca7093e825517d4de95c20f27db929d37357716c9ae46a832e95bbe2e8dda"
|
||||
],
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": {
|
||||
"hash": "c4f6cfee065af559612a5c58a1775e3780d3d492d2d927b6bfdadba1eb626269",
|
||||
"sum": "1500"
|
||||
},
|
||||
"script_version": 0,
|
||||
"script_key": "02bdccf6e4aaa9b2356cc5001d444a7b9f7a5ad9c6da85236230be3d7be0b5bcff",
|
||||
"group_key": null
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": [
|
||||
{
|
||||
"output_index": 1,
|
||||
"internal_key": "0210ee8178e18046d105421c67c2e334f7432d458df1d460492d947e1357bacfe8",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0001ca33245063350720fab0d245ba29b6d7ac15548847358e986986f435c5c9cef900000000000004b0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
{
|
||||
"output_index": 2,
|
||||
"internal_key": "02fc54f2740d5cba24638d7a488ea23d93b2205d5a4bdffe4c59ac8587128495ed",
|
||||
"commitment_proof": null,
|
||||
"tapscript_proof": {
|
||||
"tap_preimage_1": "",
|
||||
"tap_preimage_2": "",
|
||||
"bip86": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"split_root_proof": null,
|
||||
"meta_reveal": null,
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "002475bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a15000000000150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000096e88000000000000000002fd018d0200000000010206da3d8b7253faa4c9663f2124477d70d9bb93c39792d2e78ce80954144757140000000000ffffffff75bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a1500000000000000000003e8030000000000002251201aa347eeaed967cc1da29ae63e16c6b0d7e653cb8465d9678c03a5aadd469693e8030000000000002251207f80e879022a8ed063078bc89507e1727e167a924c56e82a6ac51ca977149bc94aa9f50500000000225120424ee9a5071750b1ba0b55c9f0f2613fe1e10616bfcb399c661833941daed17902483045022100e73decba204d5f83eeb1a37c6ecedad978291b5dd315fd6aa20c965a35b19fce02207b71da7bb58c371ebe08b758dd79e7f2f303776103bf9e3391389ed2b57f7aab0121035c30c18e240e7fed40d08bea7abf3fe73c79b28503aed33c32c71b5d7866d8a401403331ea969fa7be783b7411582d16fe24db46ea3f5a3da418d3c9fa47be53e4aba69903530d0615628d5abe1f65af45d2513fc07742cc28872f22148f2fa297490000000003010004fd01660001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd012c06ad01ab006575bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a15000000002fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e9301420140a78a0f6e328c20913a01cf65573cc0ea7f475e935e4c96e12acfe4071ee40b70694ca7093e825517d4de95c20f27db929d37357716c9ae46a832e95bbe2e8dda0728c4f6cfee065af559612a5c58a1775e3780d3d492d2d927b6bfdadba1eb62626900000000000005dc08020000092102bdccf6e4aaa9b2356cc5001d444a7b9f7a5ad9c6da85236230be3d7be0b5bcff05c70004000000000121021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c029c004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff014f000100014a0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf06f802c700040000000101210210ee8178e18046d105421c67c2e334f7432d458df1d460492d947e1357bacfe8029c007100010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717024a0001ca33245063350720fab0d245ba29b6d7ac15548847358e986986f435c5c9cef900000000000004b0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2e000400000002012102fc54f2740d5cba24638d7a488ea23d93b2205d5a4bdffe4c59ac8587128495ed03030201010b0400000000",
|
||||
"comment": "valid regtest proof for split root"
|
||||
},
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "154acf44a7c6c85b04d2adab29ae203a221e42040252f906f5e4da0257d8bb75:0",
|
||||
"block_header": {
|
||||
"version": 0,
|
||||
"prev_block": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"merkle_root": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"timestamp": 2288912640,
|
||||
"bits": 0,
|
||||
"nonce": 0
|
||||
},
|
||||
"block_height": 0,
|
||||
"anchor_tx": "0200000000010206da3d8b7253faa4c9663f2124477d70d9bb93c39792d2e78ce80954144757140000000000ffffffff75bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a1500000000000000000003e8030000000000002251201aa347eeaed967cc1da29ae63e16c6b0d7e653cb8465d9678c03a5aadd469693e8030000000000002251207f80e879022a8ed063078bc89507e1727e167a924c56e82a6ac51ca977149bc94aa9f50500000000225120424ee9a5071750b1ba0b55c9f0f2613fe1e10616bfcb399c661833941daed17902483045022100e73decba204d5f83eeb1a37c6ecedad978291b5dd315fd6aa20c965a35b19fce02207b71da7bb58c371ebe08b758dd79e7f2f303776103bf9e3391389ed2b57f7aab0121035c30c18e240e7fed40d08bea7abf3fe73c79b28503aed33c32c71b5d7866d8a401403331ea969fa7be783b7411582d16fe24db46ea3f5a3da418d3c9fa47be53e4aba69903530d0615628d5abe1f65af45d2513fc07742cc28872f22148f2fa2974900000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [],
|
||||
"bits": []
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
|
||||
"genesis_tag": "first-itestbuxx",
|
||||
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
|
||||
"genesis_output_index": 0,
|
||||
"genesis_type": 0,
|
||||
"amount": 1200,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": {
|
||||
"proof": "00018fe4287d3f4255877abfd18a156db9bdc178f46fc5f828564a9d7827c5f7e3cd000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"root_asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
|
||||
"genesis_tag": "first-itestbuxx",
|
||||
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
|
||||
"genesis_output_index": 0,
|
||||
"genesis_type": 0,
|
||||
"amount": 300,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "154acf44a7c6c85b04d2adab29ae203a221e42040252f906f5e4da0257d8bb75:0",
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717",
|
||||
"script_key": "02aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e93"
|
||||
},
|
||||
"tx_witness": [
|
||||
"a78a0f6e328c20913a01cf65573cc0ea7f475e935e4c96e12acfe4071ee40b70694ca7093e825517d4de95c20f27db929d37357716c9ae46a832e95bbe2e8dda"
|
||||
],
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": {
|
||||
"hash": "c4f6cfee065af559612a5c58a1775e3780d3d492d2d927b6bfdadba1eb626269",
|
||||
"sum": "1500"
|
||||
},
|
||||
"script_version": 0,
|
||||
"script_key": "02bdccf6e4aaa9b2356cc5001d444a7b9f7a5ad9c6da85236230be3d7be0b5bcff",
|
||||
"group_key": null
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef3",
|
||||
"group_key": null
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 1,
|
||||
"internal_key": "0210ee8178e18046d105421c67c2e334f7432d458df1d460492d947e1357bacfe8",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": [
|
||||
{
|
||||
"output_index": 0,
|
||||
"internal_key": "021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0001e3e1286f38832ae9a5c7b7ab1f9ee5c2e27b5a45a85fc51e39a8a427ebb87958000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
{
|
||||
"output_index": 2,
|
||||
"internal_key": "02fc54f2740d5cba24638d7a488ea23d93b2205d5a4bdffe4c59ac8587128495ed",
|
||||
"commitment_proof": null,
|
||||
"tapscript_proof": {
|
||||
"tap_preimage_1": "",
|
||||
"tap_preimage_2": "",
|
||||
"bip86": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"split_root_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"meta_reveal": null,
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "002475bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a15000000000150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000096e88000000000000000002fd018d0200000000010206da3d8b7253faa4c9663f2124477d70d9bb93c39792d2e78ce80954144757140000000000ffffffff75bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a1500000000000000000003e8030000000000002251201aa347eeaed967cc1da29ae63e16c6b0d7e653cb8465d9678c03a5aadd469693e8030000000000002251207f80e879022a8ed063078bc89507e1727e167a924c56e82a6ac51ca977149bc94aa9f50500000000225120424ee9a5071750b1ba0b55c9f0f2613fe1e10616bfcb399c661833941daed17902483045022100e73decba204d5f83eeb1a37c6ecedad978291b5dd315fd6aa20c965a35b19fce02207b71da7bb58c371ebe08b758dd79e7f2f303776103bf9e3391389ed2b57f7aab0121035c30c18e240e7fed40d08bea7abf3fe73c79b28503aed33c32c71b5d7866d8a401403331ea969fa7be783b7411582d16fe24db46ea3f5a3da418d3c9fa47be53e4aba69903530d0615628d5abe1f65af45d2513fc07742cc28872f22148f2fa297490000000003010004fd02b40001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd04b006fd022301fd021f0065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fd01b44a00018fe4287d3f4255877abfd18a156db9bdc178f46fc5f828564a9d7827c5f7e3cd000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffd01660001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd012c06ad01ab006575bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a15000000002fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e9301420140a78a0f6e328c20913a01cf65573cc0ea7f475e935e4c96e12acfe4071ee40b70694ca7093e825517d4de95c20f27db929d37357716c9ae46a832e95bbe2e8dda0728c4f6cfee065af559612a5c58a1775e3780d3d492d2d927b6bfdadba1eb62626900000000000005dc08020000092102bdccf6e4aaa9b2356cc5001d444a7b9f7a5ad9c6da85236230be3d7be0b5bcff08020000092102a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef3059f00040000000101210210ee8178e18046d105421c67c2e334f7432d458df1d460492d947e1357bacfe80274004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff06fd012002ef0004000000000121021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c02c4007100010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717024a0001e3e1286f38832ae9a5c7b7ab1f9ee5c2e27b5a45a85fc51e39a8a427ebb87958000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f014f000100014a0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf2e000400000002012102fc54f2740d5cba24638d7a488ea23d93b2205d5a4bdffe4c59ac8587128495ed030302010107c70004000000000121021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c029c004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff014f000100014a0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf0b0400000000",
|
||||
"comment": "valid regtest split proof"
|
||||
},
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "a3e48a863ca2e83c4759a7909c8a6a0766e53a9f6c647bc7e1206f32cc543fff:1",
|
||||
"block_header": {
|
||||
"version": 541065216,
|
||||
"prev_block": "6f4a14b01002d14c538065d2f9264c224231c995c7e96929bc350b28364fefcc",
|
||||
"merkle_root": "1ad4f663df73cb525aea66ee5c4e7298c721feeabb5f139b270be353363b16d0",
|
||||
"timestamp": 1693480105,
|
||||
"bits": 545259519,
|
||||
"nonce": 2
|
||||
},
|
||||
"block_height": 444,
|
||||
"anchor_tx": "0200000000010200d54317c4d2f29bc331369eb587f71fe0cc7d7d74883c606a45f0c641792e410000000000ffffffffff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a301000000000000000003e803000000000000225120cff975615b0a36601e15e74541547f920db0724132db0fe0742b2a866f5f9028e803000000000000225120cd1386d8a2e2f573c90a1a8fb4b40fd570d2d03c651ee6e6f5a295bfa27c23e04aa9f5050000000022512083cb5a723299742bbeac9269a920bd8155e42d13543aa77dc7a872b6db31e57e0247304402203f7fdbb53d5bc5dcd8241505e10dc63ed1099b1379a87a044f190814fc2e962e02202dc271496799e9620d705578fa5c9e41ac08a259d74e6db13ac854902856f726012103549d04fb9cbe86c2411910c7e12e9937f28a1e9628f206adc7ebb3830103c6d70140fac493960b98357f9e1a28e3c2aa9b1220730126e8d0d9a6a46665f08c1b006a4734c8527ff4a569bc2b643c2228c8282060308223a5341b58126756f50285e800000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [
|
||||
"acdaf9ef85967c188235d6048f6c0fef91bedf570c199f3c9d9cbd27f7294aed"
|
||||
],
|
||||
"bits": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
|
||||
"genesis_tag": "first-itestbuxx",
|
||||
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
|
||||
"genesis_output_index": 0,
|
||||
"genesis_type": 0,
|
||||
"amount": 500,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": {
|
||||
"proof": "0001be64e9b8bf8d9f92192dcde61f2c727fad5740d0dd91e72c47f75c8eeed4a80900000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"root_asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
|
||||
"genesis_tag": "first-itestbuxx",
|
||||
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
|
||||
"genesis_output_index": 0,
|
||||
"genesis_type": 0,
|
||||
"amount": 700,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "a3e48a863ca2e83c4759a7909c8a6a0766e53a9f6c647bc7e1206f32cc543fff:1",
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717",
|
||||
"script_key": "02a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef3"
|
||||
},
|
||||
"tx_witness": [
|
||||
"731afca17f759d2da8a7499b34bbebd843eeb9a41053a0e2f9c4a9688f807c5673904c65c53e7d3a16224adbb5ead039364d060b5e114832d9ff743a87142715"
|
||||
],
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": {
|
||||
"hash": "5276ca3e8ed5edfe1d663864cc9d4b55d317310ad11b9b4af484762821e5a627",
|
||||
"sum": "1200"
|
||||
},
|
||||
"script_version": 0,
|
||||
"script_key": "02e96e7a98868e359456d045b486ca3344e9f5ad860e8a402bf34bf73bc77d2a6e",
|
||||
"group_key": null
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02dd084859b6233728659a35052a1dde96cc2ba92ed813d8d5be0d9e103178ee16",
|
||||
"group_key": null
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 1,
|
||||
"internal_key": "024bc42417867894cadb917276991607150457fc3481ab4b3fe73e98b7d9c463b7",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": [
|
||||
{
|
||||
"output_index": 0,
|
||||
"internal_key": "03204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "000163fc2d75ff3a9b49efaa0a407de981fd1997ff736eabe8277cac7ddd261af97f00000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
{
|
||||
"output_index": 2,
|
||||
"internal_key": "02a6f0dc7b8aefc5faaf73888b3323a6ba4a26a779cae4b5f6b78c7d12ec82b123",
|
||||
"commitment_proof": null,
|
||||
"tapscript_proof": {
|
||||
"tap_preimage_1": "",
|
||||
"tap_preimage_2": "",
|
||||
"bip86": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"split_root_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "03204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"meta_reveal": null,
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": [
|
||||
"bbb66f7d3cd53b00143cf01fd9f71b65f1c93e2074c18ebe4e290c24e4c3cbdb81d66b568b498f4f9b10759684a0f5d43761c17421ec0b9c163e73e217f9eec3"
|
||||
]
|
||||
},
|
||||
"expected": "0024ff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a300000001015000004020ccef4f36280b35bc2969e9c795c93142224c26f9d26580534cd10210b0144a6fd0163b3653e30b279b135fbbeafe21c798724e5cee66ea5a52cb73df63f6d41aa974f064ffff7f200200000002fd018c0200000000010200d54317c4d2f29bc331369eb587f71fe0cc7d7d74883c606a45f0c641792e410000000000ffffffffff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a301000000000000000003e803000000000000225120cff975615b0a36601e15e74541547f920db0724132db0fe0742b2a866f5f9028e803000000000000225120cd1386d8a2e2f573c90a1a8fb4b40fd570d2d03c651ee6e6f5a295bfa27c23e04aa9f5050000000022512083cb5a723299742bbeac9269a920bd8155e42d13543aa77dc7a872b6db31e57e0247304402203f7fdbb53d5bc5dcd8241505e10dc63ed1099b1379a87a044f190814fc2e962e02202dc271496799e9620d705578fa5c9e41ac08a259d74e6db13ac854902856f726012103549d04fb9cbe86c2411910c7e12e9937f28a1e9628f206adc7ebb3830103c6d70140fac493960b98357f9e1a28e3c2aa9b1220730126e8d0d9a6a46665f08c1b006a4734c8527ff4a569bc2b643c2228c8282060308223a5341b58126756f50285e800000000032201ed4a29f727bd9c9d3c9f190c57dfbe91ef0f6c8f04d63582187c9685eff9daac0004fd02b40001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd01f406fd022301fd021f0065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fd01b44a0001be64e9b8bf8d9f92192dcde61f2c727fad5740d0dd91e72c47f75c8eeed4a80900000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffd01660001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd02bc06ad01ab0065ff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a3000000012fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef301420140731afca17f759d2da8a7499b34bbebd843eeb9a41053a0e2f9c4a9688f807c5673904c65c53e7d3a16224adbb5ead039364d060b5e114832d9ff743a8714271507285276ca3e8ed5edfe1d663864cc9d4b55d317310ad11b9b4af484762821e5a62700000000000004b008020000092102e96e7a98868e359456d045b486ca3344e9f5ad860e8a402bf34bf73bc77d2a6e08020000092102dd084859b6233728659a35052a1dde96cc2ba92ed813d8d5be0d9e103178ee16059f0004000000010121024bc42417867894cadb917276991607150457fc3481ab4b3fe73e98b7d9c463b70274004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff06f802c7000400000000012103204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d029c007100010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717024a000163fc2d75ff3a9b49efaa0a407de981fd1997ff736eabe8277cac7ddd261af97f00000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2e000400000002012102a6f0dc7b8aefc5faaf73888b3323a6ba4a26a779cae4b5f6b78c7d12ec82b1230303020101079f000400000000012103204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d0274004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a420140bbb66f7d3cd53b00143cf01fd9f71b65f1c93e2074c18ebe4e290c24e4c3cbdb81d66b568b498f4f9b10759684a0f5d43761c17421ec0b9c163e73e217f9eec30b04000001bc",
|
||||
"comment": "valid regtest ownership proof"
|
||||
},
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
|
||||
"block_header": {
|
||||
"version": 541065216,
|
||||
"prev_block": "44d3b42cf499c0e5c7ce75cb2b9d293b161361101620108c873d4e90772221e6",
|
||||
"merkle_root": "e3a640f85a22dcf6082c8279aacae8bcbf58183b50e75efc05a844a88dbcff79",
|
||||
"timestamp": 1693480105,
|
||||
"bits": 545259519,
|
||||
"nonce": 0
|
||||
},
|
||||
"block_height": 441,
|
||||
"anchor_tx": "02000000000101005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a0000000000ffffffff02e803000000000000225120c5532da05265abb1b740828a423046bc2b38fab6f4deb8a13fc64f59be9fc001debcf50500000000225120b061c4c81aed3d158ad8abbeda73fa76389323e53461ae3727894e4ffe582c0e02483045022100a3c7343891257da013708411998c8f685dbe1e77c0a222bf11227d79a29a9a6002205f4330bc32e5f0f8836db23b21c8b640490153e1403bb1a80998960bfbec3a6101210381c26249078b3fb3ad2387ff1ce4d8153dddf7258bc5b58b409fcd16d3df9d5900000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [
|
||||
"18791a381a48962338b8f5b0b882adee702b3b13c8a76127aaca77b169ac08dd"
|
||||
],
|
||||
"bits": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
|
||||
"genesis_tag": "first-itestbuxx",
|
||||
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
|
||||
"genesis_output_index": 0,
|
||||
"genesis_type": 0,
|
||||
"amount": 1500,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e93",
|
||||
"group_key": null
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "02fa4d23d048dbc292f69a5ca081b9f0b3c5cb4886b7f1767428609e375479345d",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "000129606637cd38716268bf1cca64ae036c73d5fa95e1258d56085128a30d2b087f00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": [
|
||||
{
|
||||
"output_index": 1,
|
||||
"internal_key": "024201da6b9645e123229f440ff1007691251a3b8a5d85c8321e28d640d61163da",
|
||||
"commitment_proof": null,
|
||||
"tapscript_proof": {
|
||||
"tap_preimage_1": "",
|
||||
"tap_preimage_2": "",
|
||||
"bip86": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"split_root_proof": null,
|
||||
"meta_reveal": {
|
||||
"type": 0,
|
||||
"data": "69746573742d6d65746164617461"
|
||||
},
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "0024005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a00000000015000004020e6212277904e3d878c102016106113163b299d2bcb75cec7e5c099f42cb4d34479ffbc8da844a805fc5ee7503b1858bfbce8caaa79822c08f6dc225af840a6e3a974f064ffff7f200000000002f702000000000101005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a0000000000ffffffff02e803000000000000225120c5532da05265abb1b740828a423046bc2b38fab6f4deb8a13fc64f59be9fc001debcf50500000000225120b061c4c81aed3d158ad8abbeda73fa76389323e53461ae3727894e4ffe582c0e02483045022100a3c7343891257da013708411998c8f685dbe1e77c0a222bf11227d79a29a9a6002205f4330bc32e5f0f8836db23b21c8b640490153e1403bb1a80998960bfbec3a6101210381c26249078b3fb3ad2387ff1ce4d8153dddf7258bc5b58b409fcd16d3df9d5900000000032201dd08ac69b177caaa2761a7c8133b2b70eead82b8b0f5b8382396481a381a79180004f80001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd05dc066901670065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008020000092102aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e9305c7000400000000012102fa4d23d048dbc292f69a5ca081b9f0b3c5cb4886b7f1767428609e375479345d029c004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff014f000100014a000129606637cd38716268bf1cca64ae036c73d5fa95e1258d56085128a30d2b087f00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf0630012e0004000000010121024201da6b9645e123229f440ff1007691251a3b8a5d85c8321e28d640d61163da03030201010813000100010e69746573742d6d657461646174610b04000001b9",
|
||||
"comment": "valid regtest proof file index 0"
|
||||
},
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "154acf44a7c6c85b04d2adab29ae203a221e42040252f906f5e4da0257d8bb75:0",
|
||||
"block_header": {
|
||||
"version": 541065216,
|
||||
"prev_block": "1f69c24c7fdfe348927099ebc9465b6bc76f26684079fe5cbb80762d817aa62e",
|
||||
"merkle_root": "fc22bfd5edea2d6ecaa858e7170e61c7ba52d0bdb02a3a10d78319dd93d51bae",
|
||||
"timestamp": 1693480105,
|
||||
"bits": 545259519,
|
||||
"nonce": 1
|
||||
},
|
||||
"block_height": 442,
|
||||
"anchor_tx": "0200000000010206da3d8b7253faa4c9663f2124477d70d9bb93c39792d2e78ce80954144757140000000000ffffffff75bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a1500000000000000000003e8030000000000002251201aa347eeaed967cc1da29ae63e16c6b0d7e653cb8465d9678c03a5aadd469693e8030000000000002251207f80e879022a8ed063078bc89507e1727e167a924c56e82a6ac51ca977149bc94aa9f50500000000225120424ee9a5071750b1ba0b55c9f0f2613fe1e10616bfcb399c661833941daed17902483045022100e73decba204d5f83eeb1a37c6ecedad978291b5dd315fd6aa20c965a35b19fce02207b71da7bb58c371ebe08b758dd79e7f2f303776103bf9e3391389ed2b57f7aab0121035c30c18e240e7fed40d08bea7abf3fe73c79b28503aed33c32c71b5d7866d8a401403331ea969fa7be783b7411582d16fe24db46ea3f5a3da418d3c9fa47be53e4aba69903530d0615628d5abe1f65af45d2513fc07742cc28872f22148f2fa2974900000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [
|
||||
"f4deee6295b812281f0277d9e1b3f3d8c4d8b5634bc91cd10c4d02942f23261e"
|
||||
],
|
||||
"bits": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
|
||||
"genesis_tag": "first-itestbuxx",
|
||||
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
|
||||
"genesis_output_index": 0,
|
||||
"genesis_type": 0,
|
||||
"amount": 1200,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": {
|
||||
"proof": "00018fe4287d3f4255877abfd18a156db9bdc178f46fc5f828564a9d7827c5f7e3cd000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"root_asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
|
||||
"genesis_tag": "first-itestbuxx",
|
||||
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
|
||||
"genesis_output_index": 0,
|
||||
"genesis_type": 0,
|
||||
"amount": 300,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "154acf44a7c6c85b04d2adab29ae203a221e42040252f906f5e4da0257d8bb75:0",
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717",
|
||||
"script_key": "02aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e93"
|
||||
},
|
||||
"tx_witness": [
|
||||
"a78a0f6e328c20913a01cf65573cc0ea7f475e935e4c96e12acfe4071ee40b70694ca7093e825517d4de95c20f27db929d37357716c9ae46a832e95bbe2e8dda"
|
||||
],
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": {
|
||||
"hash": "c4f6cfee065af559612a5c58a1775e3780d3d492d2d927b6bfdadba1eb626269",
|
||||
"sum": "1500"
|
||||
},
|
||||
"script_version": 0,
|
||||
"script_key": "02bdccf6e4aaa9b2356cc5001d444a7b9f7a5ad9c6da85236230be3d7be0b5bcff",
|
||||
"group_key": null
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef3",
|
||||
"group_key": null
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 1,
|
||||
"internal_key": "0210ee8178e18046d105421c67c2e334f7432d458df1d460492d947e1357bacfe8",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": [
|
||||
{
|
||||
"output_index": 0,
|
||||
"internal_key": "021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0001e3e1286f38832ae9a5c7b7ab1f9ee5c2e27b5a45a85fc51e39a8a427ebb87958000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
{
|
||||
"output_index": 2,
|
||||
"internal_key": "02fc54f2740d5cba24638d7a488ea23d93b2205d5a4bdffe4c59ac8587128495ed",
|
||||
"commitment_proof": null,
|
||||
"tapscript_proof": {
|
||||
"tap_preimage_1": "",
|
||||
"tap_preimage_2": "",
|
||||
"bip86": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"split_root_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"meta_reveal": null,
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "002475bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a15000000000150000040202ea67a812d7680bb5cfe794068266fc76b5b46c9eb99709248e3df7f4cc2691fae1bd593dd1983d7103a2ab0bdd052bac7610e17e758a8ca6e2deaedd5bf22fca974f064ffff7f200100000002fd018d0200000000010206da3d8b7253faa4c9663f2124477d70d9bb93c39792d2e78ce80954144757140000000000ffffffff75bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a1500000000000000000003e8030000000000002251201aa347eeaed967cc1da29ae63e16c6b0d7e653cb8465d9678c03a5aadd469693e8030000000000002251207f80e879022a8ed063078bc89507e1727e167a924c56e82a6ac51ca977149bc94aa9f50500000000225120424ee9a5071750b1ba0b55c9f0f2613fe1e10616bfcb399c661833941daed17902483045022100e73decba204d5f83eeb1a37c6ecedad978291b5dd315fd6aa20c965a35b19fce02207b71da7bb58c371ebe08b758dd79e7f2f303776103bf9e3391389ed2b57f7aab0121035c30c18e240e7fed40d08bea7abf3fe73c79b28503aed33c32c71b5d7866d8a401403331ea969fa7be783b7411582d16fe24db46ea3f5a3da418d3c9fa47be53e4aba69903530d0615628d5abe1f65af45d2513fc07742cc28872f22148f2fa29749000000000322011e26232f94024d0cd11cc94b63b5d8c4d8f3b3e1d977021f2812b89562eedef40004fd02b40001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd04b006fd022301fd021f0065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fd01b44a00018fe4287d3f4255877abfd18a156db9bdc178f46fc5f828564a9d7827c5f7e3cd000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffd01660001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd012c06ad01ab006575bbd85702dae4f506f9520204421e223a20ae29abadd2045bc8c6a744cf4a15000000002fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702aeac4986e8c72460b6a751e413e4c7216df677d9d4bf4bae1c63c8c300853e9301420140a78a0f6e328c20913a01cf65573cc0ea7f475e935e4c96e12acfe4071ee40b70694ca7093e825517d4de95c20f27db929d37357716c9ae46a832e95bbe2e8dda0728c4f6cfee065af559612a5c58a1775e3780d3d492d2d927b6bfdadba1eb62626900000000000005dc08020000092102bdccf6e4aaa9b2356cc5001d444a7b9f7a5ad9c6da85236230be3d7be0b5bcff08020000092102a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef3059f00040000000101210210ee8178e18046d105421c67c2e334f7432d458df1d460492d947e1357bacfe80274004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff06fd012002ef0004000000000121021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c02c4007100010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717024a0001e3e1286f38832ae9a5c7b7ab1f9ee5c2e27b5a45a85fc51e39a8a427ebb87958000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f014f000100014a0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf2e000400000002012102fc54f2740d5cba24638d7a488ea23d93b2205d5a4bdffe4c59ac8587128495ed030302010107c70004000000000121021dd27d0f30c2c04f15af5c35ee88b6d311bfba00c2eeb89341a2be606ea8934c029c004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff014f000100014a0001f1379cd74bd8dc03af86afd7d81b4f88a754896c463780c3ae2c46e2c7080f2b00000000000007d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf0b04000001ba",
|
||||
"comment": "valid regtest proof file index 1"
|
||||
},
|
||||
{
|
||||
"proof": {
|
||||
"prev_out": "a3e48a863ca2e83c4759a7909c8a6a0766e53a9f6c647bc7e1206f32cc543fff:1",
|
||||
"block_header": {
|
||||
"version": 541065216,
|
||||
"prev_block": "6f4a14b01002d14c538065d2f9264c224231c995c7e96929bc350b28364fefcc",
|
||||
"merkle_root": "1ad4f663df73cb525aea66ee5c4e7298c721feeabb5f139b270be353363b16d0",
|
||||
"timestamp": 1693480105,
|
||||
"bits": 545259519,
|
||||
"nonce": 2
|
||||
},
|
||||
"block_height": 444,
|
||||
"anchor_tx": "0200000000010200d54317c4d2f29bc331369eb587f71fe0cc7d7d74883c606a45f0c641792e410000000000ffffffffff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a301000000000000000003e803000000000000225120cff975615b0a36601e15e74541547f920db0724132db0fe0742b2a866f5f9028e803000000000000225120cd1386d8a2e2f573c90a1a8fb4b40fd570d2d03c651ee6e6f5a295bfa27c23e04aa9f5050000000022512083cb5a723299742bbeac9269a920bd8155e42d13543aa77dc7a872b6db31e57e0247304402203f7fdbb53d5bc5dcd8241505e10dc63ed1099b1379a87a044f190814fc2e962e02202dc271496799e9620d705578fa5c9e41ac08a259d74e6db13ac854902856f726012103549d04fb9cbe86c2411910c7e12e9937f28a1e9628f206adc7ebb3830103c6d70140fac493960b98357f9e1a28e3c2aa9b1220730126e8d0d9a6a46665f08c1b006a4734c8527ff4a569bc2b643c2228c8282060308223a5341b58126756f50285e800000000",
|
||||
"tx_merkle_proof": {
|
||||
"nodes": [
|
||||
"acdaf9ef85967c188235d6048f6c0fef91bedf570c199f3c9d9cbd27f7294aed"
|
||||
],
|
||||
"bits": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
|
||||
"genesis_tag": "first-itestbuxx",
|
||||
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
|
||||
"genesis_output_index": 0,
|
||||
"genesis_type": 0,
|
||||
"amount": 500,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": {
|
||||
"proof": "0001be64e9b8bf8d9f92192dcde61f2c727fad5740d0dd91e72c47f75c8eeed4a80900000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"root_asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "4a7bc3d535f78fc3b3b6ccd33922455cbd87064260cbc4896625b065b7725b00:0",
|
||||
"genesis_tag": "first-itestbuxx",
|
||||
"genesis_meta_hash": "dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d",
|
||||
"genesis_output_index": 0,
|
||||
"genesis_type": 0,
|
||||
"amount": 700,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "a3e48a863ca2e83c4759a7909c8a6a0766e53a9f6c647bc7e1206f32cc543fff:1",
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717",
|
||||
"script_key": "02a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef3"
|
||||
},
|
||||
"tx_witness": [
|
||||
"731afca17f759d2da8a7499b34bbebd843eeb9a41053a0e2f9c4a9688f807c5673904c65c53e7d3a16224adbb5ead039364d060b5e114832d9ff743a87142715"
|
||||
],
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": {
|
||||
"hash": "5276ca3e8ed5edfe1d663864cc9d4b55d317310ad11b9b4af484762821e5a627",
|
||||
"sum": "1200"
|
||||
},
|
||||
"script_version": 0,
|
||||
"script_key": "02e96e7a98868e359456d045b486ca3344e9f5ad860e8a402bf34bf73bc77d2a6e",
|
||||
"group_key": null
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02dd084859b6233728659a35052a1dde96cc2ba92ed813d8d5be0d9e103178ee16",
|
||||
"group_key": null
|
||||
},
|
||||
"inclusion_proof": {
|
||||
"output_index": 1,
|
||||
"internal_key": "024bc42417867894cadb917276991607150457fc3481ab4b3fe73e98b7d9c463b7",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"exclusion_proofs": [
|
||||
{
|
||||
"output_index": 0,
|
||||
"internal_key": "03204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "000163fc2d75ff3a9b49efaa0a407de981fd1997ff736eabe8277cac7ddd261af97f00000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
{
|
||||
"output_index": 2,
|
||||
"internal_key": "02a6f0dc7b8aefc5faaf73888b3323a6ba4a26a779cae4b5f6b78c7d12ec82b123",
|
||||
"commitment_proof": null,
|
||||
"tapscript_proof": {
|
||||
"tap_preimage_1": "",
|
||||
"tap_preimage_2": "",
|
||||
"bip86": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"split_root_proof": {
|
||||
"output_index": 0,
|
||||
"internal_key": "03204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d",
|
||||
"commitment_proof": {
|
||||
"proof": {
|
||||
"asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0,
|
||||
"asset_id": "2fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717"
|
||||
},
|
||||
"taproot_asset_proof": {
|
||||
"proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"version": 0
|
||||
}
|
||||
},
|
||||
"tapscript_sibling": ""
|
||||
},
|
||||
"tapscript_proof": null
|
||||
},
|
||||
"meta_reveal": null,
|
||||
"additional_inputs": null,
|
||||
"challenge_witness": null
|
||||
},
|
||||
"expected": "0024ff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a300000001015000004020ccef4f36280b35bc2969e9c795c93142224c26f9d26580534cd10210b0144a6fd0163b3653e30b279b135fbbeafe21c798724e5cee66ea5a52cb73df63f6d41aa974f064ffff7f200200000002fd018c0200000000010200d54317c4d2f29bc331369eb587f71fe0cc7d7d74883c606a45f0c641792e410000000000ffffffffff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a301000000000000000003e803000000000000225120cff975615b0a36601e15e74541547f920db0724132db0fe0742b2a866f5f9028e803000000000000225120cd1386d8a2e2f573c90a1a8fb4b40fd570d2d03c651ee6e6f5a295bfa27c23e04aa9f5050000000022512083cb5a723299742bbeac9269a920bd8155e42d13543aa77dc7a872b6db31e57e0247304402203f7fdbb53d5bc5dcd8241505e10dc63ed1099b1379a87a044f190814fc2e962e02202dc271496799e9620d705578fa5c9e41ac08a259d74e6db13ac854902856f726012103549d04fb9cbe86c2411910c7e12e9937f28a1e9628f206adc7ebb3830103c6d70140fac493960b98357f9e1a28e3c2aa9b1220730126e8d0d9a6a46665f08c1b006a4734c8527ff4a569bc2b643c2228c8282060308223a5341b58126756f50285e800000000032201ed4a29f727bd9c9d3c9f190c57dfbe91ef0f6c8f04d63582187c9685eff9daac0004fd02b40001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd01f406fd022301fd021f0065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fd01b44a0001be64e9b8bf8d9f92192dcde61f2c727fad5740d0dd91e72c47f75c8eeed4a80900000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffd01660001000159005b72b765b0256689c4cb60420687bd5c452239d3ccb6b3c38ff735d5c37b4a000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd02bc06ad01ab0065ff3f54cc326f20e1c77b646c9f3ae566076a8a9c90a759473ce8a23c868ae4a3000000012fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702a3eaca18f57451fc2cda92d8637ce950405c339b335d21cbb2ae6fe479449ef301420140731afca17f759d2da8a7499b34bbebd843eeb9a41053a0e2f9c4a9688f807c5673904c65c53e7d3a16224adbb5ead039364d060b5e114832d9ff743a8714271507285276ca3e8ed5edfe1d663864cc9d4b55d317310ad11b9b4af484762821e5a62700000000000004b008020000092102e96e7a98868e359456d045b486ca3344e9f5ad860e8a402bf34bf73bc77d2a6e08020000092102dd084859b6233728659a35052a1dde96cc2ba92ed813d8d5be0d9e103178ee16059f0004000000010121024bc42417867894cadb917276991607150457fc3481ab4b3fe73e98b7d9c463b70274004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff06f802c7000400000000012103204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d029c007100010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec717024a000163fc2d75ff3a9b49efaa0a407de981fd1997ff736eabe8277cac7ddd261af97f00000000000002bcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2e000400000002012102a6f0dc7b8aefc5faaf73888b3323a6ba4a26a779cae4b5f6b78c7d12ec82b1230303020101079f000400000000012103204c4b922f2b567905131ec0d4116fd4e03ce6c55003e352f525c8842692df5d0274004900010001202fd779d5e4f4ae668d7395b73a2b90e7841af04fe3068c18c6d21aad8a3ec71702220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b04000001bc",
|
||||
"comment": "valid regtest proof file index 2"
|
||||
}
|
||||
],
|
||||
"error_test_cases": null
|
||||
}
|
484
bip-tap-psbt.mediawiki
Normal file
484
bip-tap-psbt.mediawiki
Normal file
|
@ -0,0 +1,484 @@
|
|||
<pre>
|
||||
BIP: ???
|
||||
Layer: Applications
|
||||
Title: Taproot Assets PSBT
|
||||
Author: Oliver Gugger <gugger@gmail.com>
|
||||
Olaoluwa Osuntokun <laolu32@gmail.com>
|
||||
Comments-Summary: No comments yet.
|
||||
Comments-URI: https://git
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Created: 2023-02-24
|
||||
License: BSD-2-Clause
|
||||
</pre>
|
||||
|
||||
==Abstract==
|
||||
|
||||
This document describes the custom fields used in the
|
||||
[[https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki|Partially
|
||||
Signed Bitcoin Transaction (PSBT, BIP-0174)]] format for Taproot Asset state
|
||||
transition transactions.
|
||||
|
||||
==Copyright==
|
||||
|
||||
This document is licensed under the 2-clause BSD license.
|
||||
|
||||
==Design==
|
||||
|
||||
A Taproot Asset state transition transaction is also referred to as a "virtual
|
||||
transaction" or asset transfer transaction. The word "virtual" is used to
|
||||
distinguish between these asset transfers that only happen in the off-chain,
|
||||
asset overlay context as opposed to "anchor" transactions, which are BTC level
|
||||
on-chain transaction that commit many asset level transfers to the Bitcoin
|
||||
chain.
|
||||
|
||||
A virtual transaction has many similarities to its Bitcoin wire transaction
|
||||
counterpart in that it spends one or more asset inputs (asset UTXOs or asset
|
||||
"coins") and creates one or more new asset outputs.
|
||||
|
||||
The main difference to a Bitcoin transaction is that a virtual asset transaction
|
||||
does not place the witness that satisfies each input's previous output script in
|
||||
the input itself but instead uses the <code>prev_asset_witnesses</code> field of
|
||||
the dedicated output that houses the split root asset.
|
||||
This allows a many-in-many-out virtual transaction to be compressed into a
|
||||
1-in-1-out transaction (as described in
|
||||
[[./bip-tap-vm.mediawiki|bip-tap-vm]]) for validation in the Taproot Asset
|
||||
Virtual Machine.
|
||||
|
||||
To assemble the full witness stack that satisfies each input's previous output
|
||||
script the transaction might need to be signed by multiple parties and/or
|
||||
devices. This requires the virtual transaction to be passed around among
|
||||
multiple participants, each adding their part (e.g. signatures) to it. Given the
|
||||
similarities of virtual transactions to existing Bitcoin transactions, the PSBT
|
||||
format was chosen as the exchange format for virtual asset state transfers as
|
||||
well, with a set of new PSBT <code><keytype></code>s as defined in this
|
||||
document.
|
||||
|
||||
==Specification==
|
||||
|
||||
A virtual transaction can only contain inputs and outputs of assets that are
|
||||
fungible among each other. Assets are considered fungible if they either have
|
||||
the same genesis ID (were minted in the same tranche) or reference the same
|
||||
<code>group_key</code> (were minted in different tranches).
|
||||
|
||||
Within a virtual transaction multiple inputs (asset coins) that have the '''same
|
||||
genesis ID''' can be merged and split the same way Bitcoin inputs can be merged
|
||||
and split again. Fungible assets with '''different genesis IDs''' (but same
|
||||
<code>group_key</code>) can be used together in the same virtual transaction in
|
||||
order to satisfy a payment request, but merging two fungible assets (with
|
||||
distinct asset IDs) into the _same_ asset UTXO is disallowed. See the
|
||||
[[./bip-tap-vm.mediawiki|bip-tap-vm]] for more details.
|
||||
|
||||
The construction of the virtual transaction outputs must follow different rules
|
||||
depending on whether the output is received in an interactive or non-interactive
|
||||
way by the recipient:
|
||||
<ul>
|
||||
<li>
|
||||
''Interactive:'' The recipient will see the full virtual transaction (e.g. as
|
||||
a PSBT), including the fully signed new asset leaf. They have all the required
|
||||
information to be able to fully construct the BTC level anchor output Taproot
|
||||
key (including the complete asset witness and potentially multiple asset leaves
|
||||
being committed to in a single BTC level anchor output) to observe the inbound
|
||||
transfer on chain. Therefore in a scenario where a leaf is sent completely (full
|
||||
value send), a "split tombstone" (see below) is not required.
|
||||
</li>
|
||||
<li>
|
||||
''Non-interactive'': The recipient has created a Taproot Asset address and is
|
||||
only watching that Taproot output key on chain. Assets must be committed to the
|
||||
tree as a split asset, with the split commitment pruned before serializing, to
|
||||
make the resulting Taproot Asset tree completely predictable for the receiver.
|
||||
The split commitment and root asset proof will be delivered in the proof file.
|
||||
A full value send must also be created as a split with the sender creating a
|
||||
zero value "split tombstone" output with the NUMS point as the script key (see
|
||||
below).
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
TODO(guggero): Describe how fungible assets are handled in a non-interactive way
|
||||
once that is defined.
|
||||
|
||||
When splitting an asset UTXO a split commitment is created (as described in
|
||||
[[./bip-tap-vm.mediawiki|bip-tap-vm]]). The split root is placed in
|
||||
one of the outputs (often being the change output going back to the sender of
|
||||
the asset) and marked with the `IsSplitRoot` flag.
|
||||
If the remaining change of a split is 0, the <code>script_key</code> of the
|
||||
split root asset output should be the well-known NUMS point (using the string
|
||||
"taproot-assets" and the traditional "hash and increment" approach to generating
|
||||
the point) to prove the output cannot be spent further.
|
||||
This so-called "split tombstone" is required for non-interactive sends (send to
|
||||
Taproot Asset address) of the full value of a coin.
|
||||
These zero-value tombstone outputs can be pruned in an interactive scenario in
|
||||
which the recipient is a ware of the full root asset leaf (including the
|
||||
TX witness) and can construct the commitment tree root correctly.
|
||||
|
||||
==Custom PSBT fields for Taproot Asset virtual transactions==
|
||||
|
||||
[[https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki|BIP-0174]]
|
||||
defines roughly 6 global, 24 input and 7 output <code>keytype</code>s. This
|
||||
leaves enough room for new BIPs to specify additional types without a big risk
|
||||
of collision. The proprietary type <code>0xFX</code> does not apply to this case
|
||||
as that is meant for application/vendor specific data, not fields declared in
|
||||
a BIP.
|
||||
|
||||
To further reduce the risk of colliding with key types of other (in-flight) BIPs
|
||||
we start at the (arbitrarily chosen) value <code>0x70</code> for each section
|
||||
of new key types.
|
||||
|
||||
===Global types===
|
||||
|
||||
{|
|
||||
! Name
|
||||
! <tt><keytype></tt>
|
||||
! <tt><keydata></tt>
|
||||
! <tt><keydata></tt> Description
|
||||
! <tt><valuedata></tt>
|
||||
! <tt><valuedata></tt> Description
|
||||
|-
|
||||
| Virtual Transaction Marker
|
||||
| <tt>PSBT_GLOBAL_TAP_IS_VIRTUAL_TX = 0x70</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><byte 0x01></tt>
|
||||
| The static marker of <code>0x01</code> to identify this transaction as a
|
||||
Taproot Asset virtual transaction.
|
||||
|-
|
||||
| Taproot Asset Chain HRP
|
||||
| <tt>PSBT_GLOBAL_TAP_CHAIN_HRP = 0x71</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><string HRP></tt>
|
||||
| The Human Readable Prefix of the Taproot Asset chain identifier as specified
|
||||
in [[./bip-tap-addr.mediawiki|bip-tap-addr]].
|
||||
|-
|
||||
| Taproot Asset PSBT Version
|
||||
| <tt>PSBT_GLOBAL_TAP_PSBT_VERSION = 0x72</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><byte version></tt>
|
||||
| The version of the Taproot Asset PSBT format. Currently <code>0x00</code> is
|
||||
the only known and supported version.
|
||||
|}
|
||||
|
||||
===Input types===
|
||||
|
||||
{|
|
||||
! Name
|
||||
! <tt><keytype></tt>
|
||||
! <tt><keydata></tt>
|
||||
! <tt><keydata></tt> Description
|
||||
! <tt><valuedata></tt>
|
||||
! <tt><valuedata></tt> Description
|
||||
|-
|
||||
| Previous Asset Leaf
|
||||
| <tt>PSBT_IN_TAP_PREV_ID = 0x70</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><tlv_blob prev_asset_id></tt>
|
||||
| The previous asset leaf (identified by
|
||||
<code>prev_outpoint || asset_id || asset_script_hash</code>) in TLV format as
|
||||
defined in [[./bip-tap.mediawiki#asset-leaf-format|bip-tap asset leaf format]].
|
||||
|-
|
||||
| Anchor Output Value
|
||||
| <tt>PSBT_IN_TAP_ANCHOR_VALUE = 0x71</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><64-bit big endian int value></tt>
|
||||
| The value in satoshis of the BTC level anchor output that committed to the
|
||||
asset input being spent.
|
||||
|-
|
||||
| Anchor Output <code>pkScript</code>
|
||||
| <tt>PSBT_IN_TAP_ANCHOR_PK_SCRIPT = 0x72</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><bytes pkScript></tt>
|
||||
| The <code>pkScript</code> of the BTC level anchor output that committed to the
|
||||
asset input being spent.
|
||||
|-
|
||||
| Anchor Output Sighash Type
|
||||
| <tt>PSBT_IN_TAP_ANCHOR_SIGHASH_TYPE = 0x73</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><64-bit big endian int sighash type></tt>
|
||||
| The 64-bit big endian unsigned integer specifying the sighash type to be used
|
||||
for the BTC level anchor output that committed to the asset input being spent.
|
||||
|-
|
||||
| Anchor Output Taproot Internal Key
|
||||
| <tt>PSBT_IN_TAP_ANCHOR_TAP_INTERNAL_KEY = 0x74</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><32-byte xonlypubkey></tt>
|
||||
| The X-only pubkey used as the internal key of the BTC level anchor output that
|
||||
committed to the asset input being spent.
|
||||
|-
|
||||
| Anchor Output Taproot Merkle Root
|
||||
| <tt>PSBT_IN_TAP_ANCHOR_TAP_MERKLE_ROOT = 0x75</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><32-byte hash></tt>
|
||||
| The 32 byte Merkle root hash of the BTC level anchor output that committed to
|
||||
the asset input being spent.
|
||||
|-
|
||||
| Anchor Output BIP-0032 Derivation Path
|
||||
| <tt>PSBT_IN_TAP_ANCHOR_BIP32_DERIVATION = 0x76</tt>
|
||||
| <tt><bytes pubkey></tt>
|
||||
| The public key
|
||||
| <tt><4 byte fingerprint> <32-bit little endian uint path element>*</tt>
|
||||
| The master key fingerprint as defined by BIP-0032 concatenated with the
|
||||
derivation path of the public key that was used for the BTC level anchor output
|
||||
that committed to the asset input being spent. The derivation path is
|
||||
represented as 32 bit unsigned integer indexes concatenated with each other.
|
||||
Public keys are those that will be needed to sign this input.
|
||||
|-
|
||||
| Anchor Output Taproot Key BIP 32 Derivation Path
|
||||
| <tt>PSBT_IN_TAP_ANCHOR_TAP_BIP32_DERIVATION = 0x77</tt>
|
||||
| <tt><32 byte xonlypubkey></tt>
|
||||
| A 32 byte X-only public key involved in this input. It may be the output key,
|
||||
the internal key, or a key present in a leaf script.
|
||||
| <tt><compact size uint number of hashes> <32 byte leaf hash>*
|
||||
<4 byte fingerprint> <32-bit little endian uint path element>*</tt>
|
||||
| A compact size unsigned integer representing the number of leaf hashes,
|
||||
followed by a list of leaf hashes, followed by the 4 byte master key fingerprint
|
||||
concatenated with the derivation path of the public key. The derivation path is
|
||||
represented as 32-bit little endian unsigned integer indexes concatenated with
|
||||
each other. Public keys are those needed to spend this output. The leaf hashes
|
||||
are of the leaves which involve this public key. The internal key does not have
|
||||
leaf hashes, so can be indicated with a <tt>hashes len</tt> of 0. Finalizers
|
||||
should remove this field after <tt>PSBT_IN_FINAL_SCRIPTWITNESS</tt> is
|
||||
constructed.
|
||||
|-
|
||||
| Anchor Output Tapscript Sibling
|
||||
| <tt>PSBT_IN_TAP_ANCHOR_TAPSCRIPT_SIBLING = 0x78</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><byte sibling_type><compact size num_bytes><bytes tapscript sibling preimage></tt>
|
||||
| The preimage of the tapscript sibling that is on the same level as the Taproot
|
||||
Asset commitment that was committed to in the anchor. If this is not present,
|
||||
then the Taproot Asset commitment is the only script leaf in the tree.
|
||||
|-
|
||||
| Taproot Asset Asset
|
||||
| <tt>PSBT_IN_TAP_ASSET = 0x79</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><tlv_blob asset></tt>
|
||||
| The full input asset leaf that is being spent, in TLV format as defined in
|
||||
[[./bip-tap.mediawiki#asset-leaf-format|bip-tap asset leaf format]].
|
||||
|-
|
||||
| Taproot Asset Proof
|
||||
| <tt>PSBT_IN_TAP_ASSET_PROOF = 0x7a</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><tlv_blob proof></tt>
|
||||
| The last proof of the input asset being spent, in TLV format as defined in
|
||||
[[./bip-tap-proof-file.mediawiki#file-serialization|
|
||||
bip-tap-proof-file File Serialization]].
|
||||
|}
|
||||
|
||||
===Output types===
|
||||
|
||||
{|
|
||||
! Name
|
||||
! <tt><keytype></tt>
|
||||
! <tt><keydata></tt>
|
||||
! <tt><keydata></tt> Description
|
||||
! <tt><valuedata></tt>
|
||||
! <tt><valuedata></tt> Description
|
||||
|-
|
||||
| Type
|
||||
| <tt>PSBT_OUT_TAP_TYPE = 0x70</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><byte output_type></tt>
|
||||
| A <code>uint8</code> value indicating the type of the virtual output. Valid
|
||||
values are: 0x00 (<tt>Simple</tt>), 0x01 (<tt>SplitRoot</tt>),
|
||||
0x02 (<tt>PassiveAssetsOnly</tt>), 0x03 (<tt>PassiveSplitRoot</tt>), see
|
||||
description below.
|
||||
|-
|
||||
| Is Interactive
|
||||
| <tt>PSBT_OUT_TAP_IS_INTERACTIVE = 0x71</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><byte 0x00/0x01></tt>
|
||||
| A boolean value indicating whether the recipient of the output is aware of the
|
||||
full asset leaf they are receiving (=interactive) or not (=non-interactive). In
|
||||
the non-interactive case, the recipient will expect this output to be a split
|
||||
output.
|
||||
|-
|
||||
| Anchor Output Index
|
||||
| <tt>PSBT_OUT_TAP_ANCHOR_OUTPUT_INDEX = 0x72</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><64-bit big endian int value></tt>
|
||||
| The Bitcoin level anchor transaction output index this asset output is going
|
||||
to be committed to.
|
||||
|-
|
||||
| Anchor Output Taproot Internal Key
|
||||
| <tt>PSBT_OUT_TAP_ANCHOR_TAP_INTERNAL_KEY = 0x73</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><32-byte xonlypubkey></tt>
|
||||
| The X-only pubkey used as the internal key of the BTC level anchor output that
|
||||
will be committing to the asset output.
|
||||
|-
|
||||
| Anchor Output BIP-0032 Derivation Path
|
||||
| <tt>PSBT_OUT_TAP_ANCHOR_BIP32_DERIVATION = 0x74</tt>
|
||||
| <tt><bytes pubkey></tt>
|
||||
| The public key
|
||||
| <tt><4 byte fingerprint> <32-bit little endian uint path element>*</tt>
|
||||
| The master key fingerprint as defined by BIP-0032 concatenated with the
|
||||
derivation path of the public key that will be used for the BTC level anchor
|
||||
output that is committing to the asset output. The derivation path is
|
||||
represented as 32 bit unsigned integer indexes concatenated with each other.
|
||||
Public keys are those that will be needed to sign this input.
|
||||
|-
|
||||
| Anchor Output Taproot Key BIP-0032 Derivation Path
|
||||
| <tt>PSBT_OUT_TAP_ANCHOR_TAP_BIP32_DERIVATION = 0x75</tt>
|
||||
| <tt><32 byte xonlypubkey></tt>
|
||||
| A 32 byte X-only public key involved in this input. It may be the output key,
|
||||
the internal key, or a key present in a leaf script.
|
||||
| <tt><compact size uint number of hashes> <32 byte leaf hash>*
|
||||
<4 byte fingerprint> <32-bit little endian uint path element>*</tt>
|
||||
| A compact size unsigned integer representing the number of leaf hashes,
|
||||
followed by a list of leaf hashes, followed by the 4 byte master key fingerprint
|
||||
concatenated with the derivation path of the public key. The derivation path is
|
||||
represented as 32-bit little endian unsigned integer indexes concatenated with
|
||||
each other. Public keys are those needed to spend this output. The leaf hashes
|
||||
are of the leaves which involve this public key. The internal key does not have
|
||||
leaf hashes, so can be indicated with a <tt>hashes len</tt> of 0. Finalizers
|
||||
should remove this field after <tt>PSBT_IN_FINAL_SCRIPTWITNESS</tt> is
|
||||
constructed.
|
||||
|-
|
||||
| Taproot Asset
|
||||
| <tt>PSBT_OUT_TAP_ASSET = 0x76</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><tlv_blob asset></tt>
|
||||
| The full output asset leaf being created, in TLV format as defined in
|
||||
[[./bip-tap.mediawiki#asset-leaf-format|bip-tap asset leaf format]].
|
||||
|-
|
||||
| Taproot Asset Split Asset
|
||||
| <tt>PSBT_OUT_TAP_SPLIT_ASSET = 0x77</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><tlv_blob split_asset></tt>
|
||||
| In case the asset serialized in the <tt>PSBT_OUT_TAP_ASSET</tt> is a split
|
||||
root (<tt>PSBT_OUT_TAP_IS_SPLIT_ROOT=0x01</tt>), this field houses the created
|
||||
split asset at the root locator that contains the split commitment witness. This
|
||||
is used for validation only and isn't committed to in any tree. If present the
|
||||
split asset is encoded in TLV format as defined in
|
||||
[[./bip-tap.mediawiki#asset-leaf-format|bip-tap asset leaf format]].
|
||||
|-
|
||||
| Anchor Output Tapscript Sibling
|
||||
| <tt>PSBT_OUT_TAP_ANCHOR_TAPSCRIPT_SIBLING = 0x78</tt>
|
||||
| None
|
||||
| No key data
|
||||
| <tt><byte sibling_type><compact size num_bytes><bytes tapscript sibling preimage></tt>
|
||||
| The preimage of the tapscript sibling that is on the same level as the Taproot
|
||||
Asset commitment that was committed to in the anchor. If this is not present,
|
||||
then the Taproot Asset commitment is the only script leaf in the tree.
|
||||
|}
|
||||
|
||||
===Values for <tt>PSBT_OUT_TAP_TYPE</tt>===
|
||||
|
||||
The <tt>PSBT_OUT_TAP_TYPE</tt> field describes the type of virtual output. This
|
||||
type has an influence on how an asset needs to be signed or whether there is an
|
||||
asset at all in an output.
|
||||
The following values are defined:
|
||||
<ul>
|
||||
<li><b>Simple</b> (<tt>0x00</tt>) is a plain full-value or split output that is
|
||||
not a split root and does not carry passive assets. In case of a split, the
|
||||
asset of this output has a split commitment.
|
||||
</li>
|
||||
<li><b>SplitRoot</b> (<tt>0x01</tt>) is a split root output that carries the
|
||||
change from a split or a tombstone from a non-interactive full value send
|
||||
output. In either case, the asset of this output has a tx witness.
|
||||
</li>
|
||||
<li><b>PassiveAssetsOnly</b> (<tt>0x02</tt>) indicates that this output only
|
||||
carries passive assets and therefore the asset in this output is nil. The
|
||||
passive assets themselves are signed in their own virtual transactions and
|
||||
are not present in this packet.
|
||||
</li>
|
||||
<li><b>PassiveSplitRoot</b> (<tt>0x03</tt>) is a split root output that carries
|
||||
the change from a split or a tombstone from a non-interactive full value send
|
||||
output, as well as passive assets.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
==Committing Taproot Asset virtual transactions into a BTC level anchor transaction==
|
||||
|
||||
The above section defined new fields for representing a virtual asset
|
||||
transaction. This section explains how one or multiple virtual asset
|
||||
transactions can be mapped to and be committed to in a single Bitcoin level
|
||||
on-chain "anchor" transaction.
|
||||
|
||||
The following steps should be taken for committing one or more Taproot Asset
|
||||
virtual transactions onto a single BTC anchor transaction:
|
||||
# Sign the virtual transaction as described in [[./bip-tap.mediawiki|bip-tap]].
|
||||
# Validate that each input in each virtual transaction has the necessary anchor information set (<code>PSBT_IN_TAP_ANCHOR_*</code>).
|
||||
# Validate that each output in each virtual transaction has the necessary anchor information set (<code>PSBT_OUT_TAP_ANCHOR_*</code>).
|
||||
# Validate that each virtual input's anchor information referencing the same previous outpoint (<code>PSBT_IN_TAP_PREV_ID.prev_outpoint</code>) is the same as all fields should refer to the same on-chain unspent output.
|
||||
# Validate that each virtual output's anchor information referencing the same anchor output index (<code>PSBT_OUT_TAP_ANCHOR_OUTPUT_INDEX</code>) is the same as all fields should refer to the same on-chain output being created.
|
||||
# For each input, add the last transition proof of the input asset to the BTC anchor PSBT input (field <code>PSBT_IN_TAP_PROOF</code>).
|
||||
# For each unique anchor output index, create an output on the BTC anchor transaction:
|
||||
## Merge all assets into a single Taproot Asset tree.
|
||||
## If a Tapscript sibling is present for the BTC anchor output, verify it is not a Taproot Asset commitment.
|
||||
## Calculate the merkle root hash from the merged Taproot Asset tree and the optional Tapscript sibling.
|
||||
## Calculate the Taproot output key from the internal key and the merkle root hash, update the <code>pkScript</code> of the BTC anchor output.
|
||||
# Create a single transition proof for each of the virtual transaction outputs and add them to the BTC anchor output, keyed by each asset's <code>script_key</code> (field <code>PSBT_OUT_TAP_PROOF</code>).
|
||||
|
||||
Once the BTC level anchor transaction has the extra information attached, it can
|
||||
then be passed to all signers to produce the necessary signatures for getting it
|
||||
finalized.
|
||||
|
||||
==Custom PSBT fields for BTC level anchor transactions==
|
||||
|
||||
===Input types===
|
||||
|
||||
{|
|
||||
! Name
|
||||
! <tt><keytype></tt>
|
||||
! <tt><keydata></tt>
|
||||
! <tt><keydata></tt> Description
|
||||
! <tt><valuedata></tt>
|
||||
! <tt><valuedata></tt> Description
|
||||
|-
|
||||
| Taproot Asset Proof
|
||||
| <tt>PSBT_IN_TAP_PROOF = 0x70</tt>
|
||||
| <tt><32 byte xonlyscriptkey></tt>
|
||||
| The 32 byte X-only script key of the input asset being spent.
|
||||
| <tt><tlv_blob proof></tt>
|
||||
| The last proof of the input asset being spent, in TLV format as defined in
|
||||
[[./bip-tap-proof-file.mediawiki#file-serialization|bip-tap-proof-file File Serialization]].
|
||||
|}
|
||||
|
||||
===Output types===
|
||||
|
||||
{|
|
||||
! Name
|
||||
! <tt><keytype></tt>
|
||||
! <tt><keydata></tt>
|
||||
! <tt><keydata></tt> Description
|
||||
! <tt><valuedata></tt>
|
||||
! <tt><valuedata></tt> Description
|
||||
|-
|
||||
| Taproot Asset Proof
|
||||
| <tt>PSBT_OUT_TAP_PROOF = 0x70</tt>
|
||||
| <tt><32 byte xonlyscriptkey></tt>
|
||||
| The 32 byte X-only script key of the input asset being spent.
|
||||
| <tt><tlv_blob proof></tt>
|
||||
| The new transition proof(s) for the new asset(s) created in this output.
|
||||
|}
|
||||
|
||||
==Test Vectors==
|
||||
|
||||
Test vectors for [[Custom PSBT fields for Taproot Asset virtual transactions]]
|
||||
can be found here:
|
||||
* [[bip-tap-psbt/psbt_encoding_generated.json|PSBT encoding test vectors]]
|
||||
* [[bip-tap-psbt/psbt_encoding_error_cases.json|PSBT encoding error test vectors]]
|
||||
|
||||
The test vectors are automatically generated by
|
||||
[https://github.com/lightninglabs/taproot-assets/tree/main/tappsbt unit tests in
|
||||
the Taproot Assets GitHub repository].
|
||||
|
||||
==Reference Implementation==
|
||||
|
||||
github.com/lightninglabs/taproot-assets/tree/main/tappsbt
|
8
bip-tap-psbt/psbt_encoding_error_cases.json
Normal file
8
bip-tap-psbt/psbt_encoding_error_cases.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"error_test_cases": [
|
||||
{
|
||||
"packet": {},
|
||||
"error": "missing chain params HRP"
|
||||
}
|
||||
]
|
||||
}
|
395
bip-tap-psbt/psbt_encoding_generated.json
Normal file
395
bip-tap-psbt/psbt_encoding_generated.json
Normal file
|
@ -0,0 +1,395 @@
|
|||
{
|
||||
"valid_test_cases": [
|
||||
{
|
||||
"packet": {
|
||||
"inputs": [
|
||||
{
|
||||
"bip32_derivation": null,
|
||||
"tr_bip32_derivation": null,
|
||||
"tr_internal_key": "",
|
||||
"tr_merkle_root": "",
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "6abedfb7cc21821085134aec85f1ec2335aae36608efb88578042e2d29a137f2",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"anchor": {
|
||||
"value": 0,
|
||||
"pk_script": "",
|
||||
"sig_hash_type": 0,
|
||||
"internal_key": "",
|
||||
"merkle_root": "",
|
||||
"tapscript_sibling": "",
|
||||
"bip32_derivation": null,
|
||||
"tr_bip32_derivation": null
|
||||
},
|
||||
"asset": null,
|
||||
"proof": ""
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"amount": 0,
|
||||
"type": 1,
|
||||
"interactive": false,
|
||||
"anchor_output_index": 0,
|
||||
"anchor_output_internal_key": "",
|
||||
"anchor_output_bip32_derivation": null,
|
||||
"anchor_output_tr_bip32_derivation": null,
|
||||
"anchor_output_tapscript_sibling": "",
|
||||
"asset": null,
|
||||
"split_asset": null,
|
||||
"pk_script": "51207c79b9b26e463895eef5679d8558942c86c4ad2233adef01bc3e6d540b3653fe",
|
||||
"bip32_derivation": null,
|
||||
"tr_bip32_derivation": null,
|
||||
"tr_internal_key": "",
|
||||
"tr_merkle_root": ""
|
||||
},
|
||||
{
|
||||
"amount": 5263531936693774911,
|
||||
"type": 0,
|
||||
"interactive": false,
|
||||
"anchor_output_index": 1,
|
||||
"anchor_output_internal_key": "034a821d5ec008712983929de448b8afb6c24e5a1b97367b9a65b6220d7f083fe3",
|
||||
"anchor_output_bip32_derivation": null,
|
||||
"anchor_output_tr_bip32_derivation": null,
|
||||
"anchor_output_tapscript_sibling": "",
|
||||
"asset": null,
|
||||
"split_asset": null,
|
||||
"pk_script": "5120458a92cc12d01b8e8892da58ed511d398f2ce42b4d6295cf0c66346249f4d306",
|
||||
"bip32_derivation": null,
|
||||
"tr_bip32_derivation": null,
|
||||
"tr_internal_key": "",
|
||||
"tr_merkle_root": ""
|
||||
},
|
||||
{
|
||||
"amount": 0,
|
||||
"type": 0,
|
||||
"interactive": false,
|
||||
"anchor_output_index": 0,
|
||||
"anchor_output_internal_key": "",
|
||||
"anchor_output_bip32_derivation": null,
|
||||
"anchor_output_tr_bip32_derivation": null,
|
||||
"anchor_output_tapscript_sibling": "",
|
||||
"asset": null,
|
||||
"split_asset": null,
|
||||
"pk_script": "51209bfdf06c3322b3f3fde43d9c13db6b5c5882f69fbba6a958c1312f48e1c71b11",
|
||||
"bip32_derivation": null,
|
||||
"tr_bip32_derivation": null,
|
||||
"tr_internal_key": "",
|
||||
"tr_merkle_root": ""
|
||||
}
|
||||
],
|
||||
"version": 0,
|
||||
"chain_params_hrp": "tapbc"
|
||||
},
|
||||
"expected": "cHNidP8BALQCAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAIlEgfHm5sm5GOJXu9WedhViULIbErSIzre8BvD5tVAs2U/4/ao62aNILSSJRIEWKkswS0BuOiJLaWO1RHTmPLOQrTWKVzwxmNGJJ9NMGAAAAAAAAAAAiUSCb/fBsMyKz8/3kPZwT22tcWIL2n7umqVjBMS9I4ccbEQAAAAABcAEBAXEFdGFwYmMBcgEAAAFwZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGq+37fMIYIQhRNK7IXx7CM1quNmCO+4hXgELi0poTfyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXEIAAAAAAAAAAABcgABcwgAAAAAAAAAAAF1AAF4AAF6AAABcAEBAXEBAAFyCAAAAAAAAAAAAAFwAQABcQEAAXIIAAAAAAAAAAEBcyEDSoIdXsAIcSmDkp3kSLivtsJOWhuXNnuaZbYiDX8IP+MAAXABAAFxAQABcggAAAAAAAAAAAA=",
|
||||
"comment": "minimal packet"
|
||||
},
|
||||
{
|
||||
"packet": {
|
||||
"inputs": [
|
||||
{
|
||||
"bip32_derivation": [
|
||||
{
|
||||
"pub_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
|
||||
"fingerprint": 0,
|
||||
"bip32_path": [
|
||||
2147484665,
|
||||
2147483648,
|
||||
2147483771,
|
||||
0,
|
||||
456
|
||||
]
|
||||
}
|
||||
],
|
||||
"tr_bip32_derivation": [
|
||||
{
|
||||
"pub_key": "bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
|
||||
"leaf_hashes": [],
|
||||
"fingerprint": 0,
|
||||
"bip32_path": [
|
||||
2147484665,
|
||||
2147483648,
|
||||
2147483771,
|
||||
0,
|
||||
456
|
||||
]
|
||||
}
|
||||
],
|
||||
"tr_internal_key": "bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
|
||||
"tr_merkle_root": "6d65726b6c6520726f6f74",
|
||||
"prev_id": {
|
||||
"out_point": "42c29291018d7c2d968d3f71f8cb984b92f67403049442fd5ad145f422b02936:4104515131",
|
||||
"asset_id": "9d17346865fcf92b0c3a17c9028be9914eb7649c6c9347800979d1830356f2a5",
|
||||
"script_key": "035f01644ac40614b96363ba9baf1a7381a7bac742d267909edac6eebfc3eba5e7"
|
||||
},
|
||||
"anchor": {
|
||||
"value": 777,
|
||||
"pk_script": "616e63686f7220706b736372697074",
|
||||
"sig_hash_type": 3,
|
||||
"internal_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
|
||||
"merkle_root": "6d65726b6c6520726f6f74",
|
||||
"tapscript_sibling": "7369626c696e67",
|
||||
"bip32_derivation": [
|
||||
{
|
||||
"pub_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
|
||||
"fingerprint": 0,
|
||||
"bip32_path": [
|
||||
2147484665,
|
||||
2147483648,
|
||||
2147483771,
|
||||
0,
|
||||
456
|
||||
]
|
||||
}
|
||||
],
|
||||
"tr_bip32_derivation": [
|
||||
{
|
||||
"pub_key": "bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
|
||||
"leaf_hashes": [],
|
||||
"fingerprint": 0,
|
||||
"bip32_path": [
|
||||
2147484665,
|
||||
2147483648,
|
||||
2147483771,
|
||||
0,
|
||||
456
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "7d07c649581eeb39b5a315724c7af14fa459169873f5f1017fbc897d067403de:424111158",
|
||||
"genesis_tag": "24e2cafccae3a61fb586b14323a6bc8f9e7df1d929333ff993933bea6f5b3af6",
|
||||
"genesis_meta_hash": "24e2cafccae3a61fb586b14323a6bc8f9e7df1d929333ff993933bea6f5b3af6",
|
||||
"genesis_output_index": 1864800808,
|
||||
"genesis_type": 0,
|
||||
"amount": 6735196588112087611,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "022b6089025115cd1c390a01476da56cc20d9dbf4f571bc883623fb027aa2c7a98",
|
||||
"group_key": {
|
||||
"group_key": "0275c517d5ed149ebee5735da50d8cc59ac6378436e000138561abd6c437d02d13",
|
||||
"group_key_sig": "a2fbac47445855f2fdabf95ef55fd268819eed6de205e2397275ac08010d1724e1edb93f6d656719896df16c350f5004b8ad5913f043b5648b3b70bf98b01a0e"
|
||||
}
|
||||
},
|
||||
"proof": "7468697320697320612070726f6f66"
|
||||
},
|
||||
{
|
||||
"bip32_derivation": null,
|
||||
"tr_bip32_derivation": null,
|
||||
"tr_internal_key": "",
|
||||
"tr_merkle_root": "",
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"anchor": {
|
||||
"value": 0,
|
||||
"pk_script": "",
|
||||
"sig_hash_type": 0,
|
||||
"internal_key": "",
|
||||
"merkle_root": "",
|
||||
"tapscript_sibling": "",
|
||||
"bip32_derivation": null,
|
||||
"tr_bip32_derivation": null
|
||||
},
|
||||
"asset": null,
|
||||
"proof": ""
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"amount": 123,
|
||||
"type": 1,
|
||||
"interactive": true,
|
||||
"anchor_output_index": 0,
|
||||
"anchor_output_internal_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
|
||||
"anchor_output_bip32_derivation": [
|
||||
{
|
||||
"pub_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
|
||||
"fingerprint": 0,
|
||||
"bip32_path": [
|
||||
2147484665,
|
||||
2147483648,
|
||||
2147483771,
|
||||
0,
|
||||
456
|
||||
]
|
||||
}
|
||||
],
|
||||
"anchor_output_tr_bip32_derivation": [
|
||||
{
|
||||
"pub_key": "bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
|
||||
"leaf_hashes": [],
|
||||
"fingerprint": 0,
|
||||
"bip32_path": [
|
||||
2147484665,
|
||||
2147483648,
|
||||
2147483771,
|
||||
0,
|
||||
456
|
||||
]
|
||||
}
|
||||
],
|
||||
"anchor_output_tapscript_sibling": "00c0126e6f7420612076616c696420736372697074",
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "f665a6a780ea967cd7101f46e83699caf3a08e4b738b68290b0d22050143a661:2783629501",
|
||||
"genesis_tag": "993ebdf888b04883e56a156a8de563afa467d49dec6a40e9a1d007f033c28230",
|
||||
"genesis_meta_hash": "993ebdf888b04883e56a156a8de563afa467d49dec6a40e9a1d007f033c28230",
|
||||
"genesis_output_index": 637353343,
|
||||
"genesis_type": 0,
|
||||
"amount": 8267293389953062912,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02b2d0d9435b2a97e09da73665048bfadcebfbe17b6fa572d955bc11e5d665f689",
|
||||
"group_key": {
|
||||
"group_key": "023a8b6353a798347b45a15b2c2348799aaa3a3290f1bd91896b310b01acf3b572",
|
||||
"group_key_sig": "de8faf83e95caae8472ca4b268ebaa6940c5166616999c71344c1b9fda5af81a515e31f183b1a4e7957beb4241f0e264c1b52935524710fa6f7a39787417bba5"
|
||||
}
|
||||
},
|
||||
"split_asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "f665a6a780ea967cd7101f46e83699caf3a08e4b738b68290b0d22050143a661:2783629501",
|
||||
"genesis_tag": "993ebdf888b04883e56a156a8de563afa467d49dec6a40e9a1d007f033c28230",
|
||||
"genesis_meta_hash": "993ebdf888b04883e56a156a8de563afa467d49dec6a40e9a1d007f033c28230",
|
||||
"genesis_output_index": 637353343,
|
||||
"genesis_type": 0,
|
||||
"amount": 8267293389953062912,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02b2d0d9435b2a97e09da73665048bfadcebfbe17b6fa572d955bc11e5d665f689",
|
||||
"group_key": {
|
||||
"group_key": "023a8b6353a798347b45a15b2c2348799aaa3a3290f1bd91896b310b01acf3b572",
|
||||
"group_key_sig": "de8faf83e95caae8472ca4b268ebaa6940c5166616999c71344c1b9fda5af81a515e31f183b1a4e7957beb4241f0e264c1b52935524710fa6f7a39787417bba5"
|
||||
}
|
||||
},
|
||||
"pk_script": "5120b2d0d9435b2a97e09da73665048bfadcebfbe17b6fa572d955bc11e5d665f689",
|
||||
"bip32_derivation": null,
|
||||
"tr_bip32_derivation": null,
|
||||
"tr_internal_key": "",
|
||||
"tr_merkle_root": ""
|
||||
},
|
||||
{
|
||||
"amount": 345,
|
||||
"type": 1,
|
||||
"interactive": false,
|
||||
"anchor_output_index": 1,
|
||||
"anchor_output_internal_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
|
||||
"anchor_output_bip32_derivation": [
|
||||
{
|
||||
"pub_key": "02bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
|
||||
"fingerprint": 0,
|
||||
"bip32_path": [
|
||||
2147484665,
|
||||
2147483648,
|
||||
2147483771,
|
||||
0,
|
||||
456
|
||||
]
|
||||
}
|
||||
],
|
||||
"anchor_output_tr_bip32_derivation": [
|
||||
{
|
||||
"pub_key": "bf8fe2f725f33573b77e69e83c36f0d76d375cdbc1e3508550cc59c5b627c90c",
|
||||
"leaf_hashes": [],
|
||||
"fingerprint": 0,
|
||||
"bip32_path": [
|
||||
2147484665,
|
||||
2147483648,
|
||||
2147483771,
|
||||
0,
|
||||
456
|
||||
]
|
||||
}
|
||||
],
|
||||
"anchor_output_tapscript_sibling": "01197ce22d12bc5a99587533af41169fa1dc9ff866c0d4d3021158d62933672d11197ce22d12bc5a99587533af41169fa1dc9ff866c0d4d3021158d62933672d11",
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "f665a6a780ea967cd7101f46e83699caf3a08e4b738b68290b0d22050143a661:2783629501",
|
||||
"genesis_tag": "993ebdf888b04883e56a156a8de563afa467d49dec6a40e9a1d007f033c28230",
|
||||
"genesis_meta_hash": "993ebdf888b04883e56a156a8de563afa467d49dec6a40e9a1d007f033c28230",
|
||||
"genesis_output_index": 637353343,
|
||||
"genesis_type": 0,
|
||||
"amount": 8267293389953062912,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02b2d0d9435b2a97e09da73665048bfadcebfbe17b6fa572d955bc11e5d665f689",
|
||||
"group_key": {
|
||||
"group_key": "023a8b6353a798347b45a15b2c2348799aaa3a3290f1bd91896b310b01acf3b572",
|
||||
"group_key_sig": "de8faf83e95caae8472ca4b268ebaa6940c5166616999c71344c1b9fda5af81a515e31f183b1a4e7957beb4241f0e264c1b52935524710fa6f7a39787417bba5"
|
||||
}
|
||||
},
|
||||
"split_asset": null,
|
||||
"pk_script": "5120b2d0d9435b2a97e09da73665048bfadcebfbe17b6fa572d955bc11e5d665f689",
|
||||
"bip32_derivation": null,
|
||||
"tr_bip32_derivation": null,
|
||||
"tr_internal_key": "",
|
||||
"tr_merkle_root": ""
|
||||
}
|
||||
],
|
||||
"version": 0,
|
||||
"chain_params_hrp": "tapbc"
|
||||
},
|
||||
"expected": "cHNidP8BALICAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACewAAAAAAAAAiUSCy0NlDWyqX4J2nNmUEi/rc6/vhe2+lctlVvBHl1mX2iVkBAAAAAAAAIlEgstDZQ1sql+CdpzZlBIv63Ov74XtvpXLZVbwR5dZl9okAAAAAAXABAQFxBXRhcGJjAXIBAAAiBgK/j+L3JfM1c7d+aeg8NvDXbTdc28HjUIVQzFnFtifJDBgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhFr+P4vcl8zVzt35p6Dw28NdtN1zbweNQhVDMWcW2J8kMGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABFyC/j+L3JfM1c7d+aeg8NvDXbTdc28HjUIVQzFnFtifJDAEYC21lcmtsZSByb290AXBlNimwIvRF0Vr9QpQEA3T2kkuYy/hxP42WLXyNAZGSwkL0pe47nRc0aGX8+SsMOhfJAovpkU63ZJxsk0eACXnRgwNW8qUDXwFkSsQGFLljY7qbrxpzgae6x0LSZ5Ce2sbuv8PrpecBcQgAAAAAAAADCQFyD2FuY2hvciBwa3NjcmlwdAFzCAAAAAAAAAADAXQhAr+P4vcl8zVzt35p6Dw28NdtN1zbweNQhVDMWcW2J8kMAXULbWVya2xlIHJvb3QidgK/j+L3JfM1c7d+aeg8NvDXbTdc28HjUIVQzFnFtifJDBgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhd7+P4vcl8zVzt35p6Dw28NdtN1zbweNQhVDMWcW2J8kMGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABeAdzaWJsaW5nAXn9kgEAAQABit4DdAZ9ibx/AfH1c5gWWaRP8XpMchWjtTnrHlhJxgd9GUdsNkAyNGUyY2FmY2NhZTNhNjFmYjU4NmIxNDMyM2E2YmM4ZjllN2RmMWQ5MjkzMzNmZjk5MzkzM2JlYTZmNWIzYWY2JOLK/Mrjph+1hrFDI6a8j5598dkpMz/5k5M76m9bOvZvJpooAAIBAAMJ/114OZy+2Ao7BmkBZwBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAgAACSECK2CJAlEVzRw5CgFHbaVswg2dv09XG8iDYj+wJ6osepgKYQJ1xRfV7RSevuVzXaUNjMWaxjeENuAAE4Vhq9bEN9AtE6L7rEdEWFXy/av5XvVf0miBnu1t4gXiOXJ1rAgBDRck4e25P21lZxmJbfFsNQ9QBLitWRPwQ7Vkiztwv5iwGg4Beg90aGlzIGlzIGEgcHJvb2YAAXBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcQgAAAAAAAAAAAFyAAFzCAAAAAAAAAAAAXUAAXgAAXoAAAFwAQEBcQEBAXIIAAAAAAAAAAABcyECv4/i9yXzNXO3fmnoPDbw1203XNvB41CFUMxZxbYnyQwidAK/j+L3JfM1c7d+aeg8NvDXbTdc28HjUIVQzFnFtifJDBgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhdb+P4vcl8zVzt35p6Dw28NdtN1zbweNQhVDMWcW2J8kMGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABdv2SAQABAAGKYaZDAQUiDQspaItzS46g88qZNuhGHxDXfJbqgKemZfal6tC9QDk5M2ViZGY4ODhiMDQ4ODNlNTZhMTU2YThkZTU2M2FmYTQ2N2Q0OWRlYzZhNDBlOWExZDAwN2YwMzNjMjgyMzCZPr34iLBIg+VqFWqN5WOvpGfUnexqQOmh0AfwM8KCMCX9PX8AAgEAAwn/crtTiUIWWAAGaQFnAGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgCAAAJIQKy0NlDWyqX4J2nNmUEi/rc6/vhe2+lctlVvBHl1mX2iQphAjqLY1OnmDR7RaFbLCNIeZqqOjKQ8b2RiWsxCwGs87Vy3o+vg+lcquhHLKSyaOuqaUDFFmYWmZxxNEwbn9pa+BpRXjHxg7Gk55V760JB8OJkwbUpNVJHEPpvejl4dBe7pQF3/ZIBAAEAAYphpkMBBSINCyloi3NLjqDzypk26EYfENd8luqAp6Zl9qXq0L1AOTkzZWJkZjg4OGIwNDg4M2U1NmExNTZhOGRlNTYzYWZhNDY3ZDQ5ZGVjNmE0MGU5YTFkMDA3ZjAzM2MyODIzMJk+vfiIsEiD5WoVao3lY6+kZ9Sd7GpA6aHQB/AzwoIwJf09fwACAQADCf9yu1OJQhZYAAZpAWcAZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAIAAAkhArLQ2UNbKpfgnac2ZQSL+tzr++F7b6Vy2VW8EeXWZfaJCmECOotjU6eYNHtFoVssI0h5mqo6MpDxvZGJazELAazztXLej6+D6Vyq6EcspLJo66ppQMUWZhaZnHE0TBuf2lr4GlFeMfGDsaTnlXvrQkHw4mTBtSk1UkcQ+m96OXh0F7ulAXgVAMASbm90IGEgdmFsaWQgc2NyaXB0AAFwAQEBcQEAAXIIAAAAAAAAAAEBcyECv4/i9yXzNXO3fmnoPDbw1203XNvB41CFUMxZxbYnyQwidAK/j+L3JfM1c7d+aeg8NvDXbTdc28HjUIVQzFnFtifJDBgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhdb+P4vcl8zVzt35p6Dw28NdtN1zbweNQhVDMWcW2J8kMGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABdv2SAQABAAGKYaZDAQUiDQspaItzS46g88qZNuhGHxDXfJbqgKemZfal6tC9QDk5M2ViZGY4ODhiMDQ4ODNlNTZhMTU2YThkZTU2M2FmYTQ2N2Q0OWRlYzZhNDBlOWExZDAwN2YwMzNjMjgyMzCZPr34iLBIg+VqFWqN5WOvpGfUnexqQOmh0AfwM8KCMCX9PX8AAgEAAwn/crtTiUIWWAAGaQFnAGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgCAAAJIQKy0NlDWyqX4J2nNmUEi/rc6/vhe2+lctlVvBHl1mX2iQphAjqLY1OnmDR7RaFbLCNIeZqqOjKQ8b2RiWsxCwGs87Vy3o+vg+lcquhHLKSyaOuqaUDFFmYWmZxxNEwbn9pa+BpRXjHxg7Gk55V760JB8OJkwbUpNVJHEPpvejl4dBe7pQF4QQEZfOItErxamVh1M69BFp+h3J/4ZsDU0wIRWNYpM2ctERl84i0SvFqZWHUzr0EWn6Hcn/hmwNTTAhFY1ikzZy0RAA==",
|
||||
"comment": "random packet"
|
||||
}
|
||||
],
|
||||
"error_test_cases": null
|
||||
}
|
718
bip-tap-universe.mediawiki
Normal file
718
bip-tap-universe.mediawiki
Normal file
|
@ -0,0 +1,718 @@
|
|||
<pre>
|
||||
BIP: ???
|
||||
Layer: Applications
|
||||
Title: Taproot Asset Universes
|
||||
Author: Olaoluwa Osuntokun <laolu32@gmail.com>
|
||||
Comments-Summary: No comments yet.
|
||||
Comments-URI: https://git
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Created: 2021-12-10
|
||||
License: BSD-2-Clause
|
||||
</pre>
|
||||
|
||||
==Abstract==
|
||||
|
||||
Taproot Asset provenance is defined by the lineage of an asset all the way back
|
||||
to the genesis point, which is the outpoint that the unique asset identifier is
|
||||
derived from. A Taproot Asset Universe is proposed as a way for users/holders
|
||||
of an asset to easily bootstrap their recognition of a given genesis point as
|
||||
the root of an asset. A Universe is an MS-SMT that indexes into the set of
|
||||
spent outpoints that track asset movement/transfer. A Universe can contain the
|
||||
set of genesis outpoints for an asset, several assets, track individual
|
||||
transactions, and also be used as an aggregation layer.
|
||||
|
||||
==Copyright==
|
||||
|
||||
This document is licensed under the 2-clause BSD license.
|
||||
|
||||
==Motivation==
|
||||
|
||||
In order to give users/holders of an asset an easy way to bootstrap provenance,
|
||||
as well as track the total amount of units issued for a given asset, an
|
||||
on-chain merkleized indexing structure is necessary. Further, if we define
|
||||
constraints w.r.t how a "canonical" Universe can be updated, then users are
|
||||
able to watch a set of on-chain outputs to be notified of further chain
|
||||
issuance. Continuing to build off this structure, if users are able to maintain
|
||||
a trust relationship with the issuer of an asset (say the asset belongs to a
|
||||
closed source game), then they can delegate update rights to a single or
|
||||
federated set of parties, allowing them to bundle several asset updates in a
|
||||
single transaction, thereby scaling on-chain transfers.
|
||||
|
||||
==Design==
|
||||
|
||||
A Taproot Asset Universe MS-SMT differs from the normal MS-SMT in that the key
|
||||
index of the lowest tree is derived from an ''outpoint'' and `script key``
|
||||
rather than an asset script key as given an outpoint where an asset ''was''
|
||||
present, the asset Universe maps to the Taproot Asset transaction+spending meta
|
||||
data. Given this outpoint indexing structure, if we create a new "re genesis"
|
||||
(to create a virtual tx graph) outpoint, then we can construct a new virtual
|
||||
Taproot Asset transaction graph which provably tracks the movement of assets in
|
||||
an off-chain manner, relying on a single or federated party to handle updates.
|
||||
|
||||
===Specification===
|
||||
|
||||
====Asset Universes====
|
||||
|
||||
An Asset Universe is a publicly audit able merkle-sum sparse merkle tree
|
||||
(MS-SMT) over one or several assets. Unlike the normal Taproot Asset tree, a
|
||||
Universe isn't used to custody Taproot Assets. Instead, a Universe commits to a
|
||||
subset of the history of one, or many assets. A close analogue to a public
|
||||
Universe is a block explorer. A Universe can be used to:
|
||||
* Bootstrap proof verification by committing to the set of genesis outputs.
|
||||
* Generate more compact proofs w/ an additional trust assumption.
|
||||
* Audit to the total amount of units in existence for a given asset.
|
||||
* Track new asset issuance for a given asset ID.
|
||||
|
||||
Universes can also be used to essentially compress the history of a series of
|
||||
transfers into a single on-chain transaction. This variant is called a Pocket
|
||||
Universe. From this PoV, a Pocket Universe can be seen as a sort of Taproot
|
||||
Asset channel wherein one party (or a consortium/threshold of them) can batch
|
||||
update a tree to clear countless transfers in a single on-chain transaction.
|
||||
Such a Universe can also be created over multiple assets, effectively becoming
|
||||
a Universe of Universes, or a ''Multiverse''.
|
||||
|
||||
During asset creation, the party creating the asset (identified by it's all
|
||||
zero <code>prev_asset_id</code> value) MAY also specify a
|
||||
<code>canonical_universe</code> field which specifies additional constraints
|
||||
on the set of outputs produced. Namely, if this field is specified during asset
|
||||
creation, then the ''first'' output of the next spend after the genesis
|
||||
outpoint MUST commit to an updated base Universe that indexes into the prior
|
||||
genesis outpoint spend (asset creation). In addition, the internal key used for
|
||||
the output MUST be the <code>asset_group_key</code> field specified during
|
||||
asset creation. After each subsequent asset issuance event, this output SHOULD
|
||||
be updated to commit to the new updated base Universe that indexes into all
|
||||
asset issuance transactions on chain.
|
||||
|
||||
Specifying a key effectively blesses a public key on-chain, allowing it to be
|
||||
used to commit to the "canonical" history of an asset. In addition, those
|
||||
wishing to be "notified" of new asset issuance can watch this output on-chain
|
||||
to track any modifications.
|
||||
|
||||
====Root Universes & Genesis Asset Verification====
|
||||
|
||||
Unlike a normal Taproot Asset asset tree, a base Universe for a given asset
|
||||
only commits to the set of ''genesis outpoints'' for an asset. The value for
|
||||
each of the leaves contains enough information to fully verify the existence of
|
||||
the transaction that created the asset. As this type of Universe only commits
|
||||
to the set of constituent assets present at the Beginning, that all other
|
||||
transfers depend on, we call this a ''Root'' Universe.
|
||||
|
||||
Such a Universe can be used to bootstrap provenance and proof verification, as
|
||||
assuming a party knows which Universe to query, they're able to verify the
|
||||
provenance of a purported valid asset. In addition to bootstrapping provenance
|
||||
verification, as Universe trees are themselves an MS-SMT, they can be used to
|
||||
audit the total amount of a given asset in existence.
|
||||
|
||||
A Root Universe, is an MS-SMT with the following structure:
|
||||
* The MS-SMT root commits to the sum of the total set of issued assets for a given <code>genesisAssetID</code>
|
||||
** A <code>genesisAssetID</code> can either be a normal <code>assetID</code> or <code>sha256(asset_group_key)</code>. In the latter case, all values in the tree MUST share the same <code>asset_group_key</code>.
|
||||
** <code>key</code>: an <code>sha256(outpoint || scriptKey)</code>. Given the asset ID, this uniquely locates a new minting event in the target outpoint.
|
||||
** <code>value</code>: <code>universe_proof_leaf</code>
|
||||
** <code>sum_value</code>: the total amount of asset units issued by the proof leaf.
|
||||
|
||||
The key of the Root Universe is a serialized Bitcoin outpoint. As a result, the
|
||||
Universe structure can be used to query for the existence of Taproot Assets
|
||||
rooted at a given outpoint. For a Root Universe, the only outpoints tracked are
|
||||
outpoints that ''create'' a Taproot Asset asset.
|
||||
|
||||
As the MS-SMT is keyed by the <code>sha256(outpoint || scriptKey)</code>, it
|
||||
can be used to bootstrap any proof verification of a purported asset, as the
|
||||
initial linkage is dependent on the provenance of the referenced
|
||||
<code>genesisOutpoint</code> (verification starts at the Beginning and works
|
||||
backwards).
|
||||
|
||||
A <code>universe_proof_leaf</code>: is the state transition proof from
|
||||
<code>bip-tap-proof-file.mediawiki</code> format:
|
||||
* type: 0 (<code>prev_out</code>)
|
||||
** value:
|
||||
*** [<code>36*byte</code>:<code>txid || output_index</code>]
|
||||
* type: 1 (<code>block_header</code>)
|
||||
** value:
|
||||
*** [<code>80*byte</code>:<code>bitcoin_header</code>]
|
||||
* type: 2 (<code>anchor_tx</code>)
|
||||
** value:
|
||||
*** [<code>...*byte</code>:<code>serialized_bitcoin_tx</code>]
|
||||
* type: 3 (<code>anchor_tx_merkle_proof</code>)
|
||||
** value:
|
||||
*** [<code>...*byte</code>:<code>merkle_inclusion_proof</code>]
|
||||
* type: 4 (<code>taproot_asset_leaf</code>)
|
||||
** value:
|
||||
*** [<code>tlv_blob</code>:<code>serialized_tlv_leaf</code>]
|
||||
* type: 5 (<code>taproot_asset_inclusion_proofs</code>)
|
||||
** value:
|
||||
*** [<code>...*byte</code>:<code>taproot_asset_taproot_proof</code>]
|
||||
**** type: 0 (<code>output_index</code>
|
||||
***** value: [<code>int32</code>:<code>index</code>]
|
||||
**** type: 1 (<code>internal_key</code>
|
||||
***** value: [<code>33*byte</code>:<code>y_parity_byte || schnorr_x_only_key</code>]
|
||||
**** type: 2 (<code>taproot_asset_proof</code>)
|
||||
***** value: [<code>...*byte</code>:<code>asset_proof</code>]
|
||||
****** type: 0 (<code>taproot_asset_proof</code>)
|
||||
******* value: [<code>...*byte</code>:<code>asset_inclusion_proof</code>]
|
||||
******* type: 0
|
||||
******** value: [<code>uint32</code>:<code>proof_version</code>]
|
||||
******* type: 1
|
||||
******** value: [<code>32*byte</code>:<code>asset_id</code>]
|
||||
******* type: 2
|
||||
******** value: [<code>...*byte</code>:<code>ms_smt_inclusion_proof</code>]
|
||||
****** type: 1 (<code>taproot_asset_inclusion_proof</code>)
|
||||
******* value: [<code>...*byte</code>:<code>taproot_asset_inclusion_proof</code>]
|
||||
******* type: 0
|
||||
******** value: [<code>uint32</code>:<code>proof_version</code>]
|
||||
******* type: 1
|
||||
******** value: [<code>...*byte</code>:<code>ms_smt_inclusion_proof</code>]
|
||||
******* type: 2 (<code>taproot_sibling_preimage</code>)
|
||||
******** value: [<code>...*byte</code>:<code>tapscript_preimage</code>]
|
||||
**** type: 3 (<code>taproot_asset_commitment_exclusion_proof</code>
|
||||
***** value: [<code>...*byte</code>:<code>taproot_exclusion_proof</code>]
|
||||
****** type: 0 (<code>tap_image_1</code>)
|
||||
******* value: [<code>...*byte</code>:<code>tapscript_preimage</code>]
|
||||
****** type: 1 (<code>tap_image_2</code>)
|
||||
******* value: [<code>...*byte</code>:<code>tapscript_preimage</code>]
|
||||
* type: 6 (<code>taproot_exclusion_proofs</code>)
|
||||
** value:
|
||||
*** [<code>uint16</code>:<code>num_proofs</code>][<code>...*byte</code>:<code>taproot_asset_taproot_proof</code>]
|
||||
|
||||
This is the same state transition proof that would be used to prove asset
|
||||
creation to a third party. The leaf value of the Root Universe allows
|
||||
verifiers to fully verify the creation of the asset based on the genesis
|
||||
outpoint spent.
|
||||
|
||||
=====Canonical Root Universe State Transition Rules=====
|
||||
|
||||
In order to provide an authoritative source of truth for the supply and
|
||||
issuance events of a given asset, an asset MAY specify a Canonical Root
|
||||
Universe at initial minting time. If the <code>canonical_universe</code> TLV is
|
||||
present in the genesis asset, then the following restrictions MUST be applied
|
||||
to subsequent transactions that spend the minting output:
|
||||
* When the minting output is spent, the ''first'' output of the resulting transaction MUST:
|
||||
** Use the internal key of the revealed <code>asset_group_key</code> as the internal key of the V1 Taproot witness program.
|
||||
** The tapscript tree of the newly created output MUST contain a new Root Universe commitment that includes the initial minting event.
|
||||
** We refer to this output as the <code>root_asset_commitment</code>.
|
||||
*** If multiple assets within a singular <code>asset_group</code> were issued in the prior transaction, then the Root Universe MUST contain all new assets.
|
||||
* For assets that were issued with an <code>asset_group_key</code>, each time a new asset is issued:
|
||||
** The latest unspent <code>root_asset_commitment</code> output MUST be spent.
|
||||
*** This serves to link new issuance events, with the reveal of a new Canonical Root Universe hash.
|
||||
** The ''first'' output of this spending transaction inherits the requirements above:
|
||||
*** A new updated Root Universe commitment is included in the <code>root_asset_commitment</code>.
|
||||
*** This new <code>root_asset_commitment</code> becomes the new updated supply anchor for the asset.
|
||||
|
||||
The stated rules above effectively serve as an iterated commit and reveal game.
|
||||
Each time a new asset is issued (the issuance commitment spent), then the first
|
||||
output of the resulting transaction MUST commit to the new Root Universe hash.
|
||||
All other subsequent issuance events MUST then spend that same output, updating
|
||||
the commitment to the Root Universe hash.
|
||||
|
||||
As a result of the above chain commitment structure, all queries against for
|
||||
the latest Canonical Root Universe of an asset can be authenticated using a
|
||||
series of merkle proofs:
|
||||
* A merkle proof anchored in the block header that mined the transaction with the <code>root_asset_commitment</code>.
|
||||
* A tapscript merkle proof to show the Root Universe hash is included in the tapscript tree.
|
||||
* A MS-SMT merkle proof to show that the asset being verified is indeed part of the Root Universe commitment chain.
|
||||
|
||||
In order to enforce uniqueness of the Root Universe has commitment, we leverage
|
||||
the same tapscript commitment uniqueness rules in
|
||||
<code>bip-tap.mediawiki</code>. We use a modified commitment structure of:
|
||||
* <code>tagged_hash("TapLeaf", leaf_version || universe_marker || universe_version || root_universe_hash)</code>
|
||||
|
||||
where:
|
||||
* <code>universe_marker</code>: is the `sha256` hash of the ascii string "universe".
|
||||
* <code>universe_version<code>: is the version of the Universe commitment used.
|
||||
* <code>root_universe_hash<code>: is the root hash of the Root Universe.
|
||||
|
||||
As the Root Universe for a given asset can be known at the initial asset
|
||||
creation time, based on the referenced <code>universeKey</code> those wishing
|
||||
to track any new asset issuance related to a given <code>genesisAssetID</code>
|
||||
can watch the output on chain. Each time the output is spent indicates a new
|
||||
minting event. As a result, clients are able to watch a select set of outputs
|
||||
on-chain, one for each <code>genesisAssetID</code> they care about, effectively
|
||||
using the blockchain to be notified each time the total amount of issued assets
|
||||
changes.
|
||||
|
||||
|
||||
====Asset Multiverses====
|
||||
|
||||
An Asset Multiverse is a Universe of Universes. Rather than just storing the
|
||||
set of constituent assets (the set of <code>genesisOutpoints</code>), a
|
||||
Multiverse commits to several root <code>assetIDs</code>, and may also commit
|
||||
to proofs of asset transfers (including splits+merges). A Multiverse is
|
||||
therefore effectively a commitment to every asset transfer that may have ever
|
||||
happened. Importantly, one cannot prove that a Multiverse has complete
|
||||
history, as a Multiverse can only commit to what it directly observed, or was
|
||||
shown to it.
|
||||
|
||||
A Multiverse has the following structure:
|
||||
* Similar to normal Taproot Asset commitments, the Multiverse itself contains two nested MS-SMT trees. The upper tree commits to the set of asset groups observed, with the inner tree committing to the transaction history of each of the asset groups.
|
||||
* Upper tree structure:
|
||||
** <code>key</code>: <code>asset_id</code> or <code>sha256(asset_key_family)</code>
|
||||
** <code>value</code>: <code>asset_group_tree_root</code>
|
||||
** <code>sum_value</code>: <code>asset_group_sum</code>
|
||||
* Inner tree structure:
|
||||
** <code>key</code>: an <code>sha256(outpoint || scriptKey)</code>, serialized in a <code>txid:vout</code> structure as we find in Bitcoin.
|
||||
** <code>value</code>: <code>universe_proof_leaf</code>
|
||||
** <code>sum_value</code>: the total amount of asset units issued by the proof leaf.
|
||||
|
||||
A Multiverse therefore commits to the set of known genesis IDs, and at a second
|
||||
level the set of complete Universe trees for each watched asset.
|
||||
|
||||
With this structure, it's possible for the maintainers of the Multiverse to
|
||||
also store subjectively complete history of the set of transfers. In addition,
|
||||
this structure can be used to trace the set of transfers/lineage for a given
|
||||
asset. Notice that we effectively commit to the set of all created outputs
|
||||
associated with an asset, with the very first spend being the
|
||||
<code>genesisOutpoint</code> spend. As a result, a full proof of an asset's
|
||||
provenance is simply a series of keys stored at the lowest level of an SMT,
|
||||
with verifies following the transfer from outpoint to outpoint within a tree.
|
||||
|
||||
Using the trait presented above, one can create a flat file that proves the
|
||||
provenance of an asset simply by extracting select branches from a Multiverse
|
||||
tree, and enumerating the set of keys one needs to assert for validation.
|
||||
|
||||
====Pocket Universes: Off-Chain Taproot Asset Transfer Compression====
|
||||
|
||||
All leaves within a Multiverse are themselves a commitment to an event that
|
||||
happened on chain: A Taproot Asset transfer. Proofs for unique assets have a nice
|
||||
property that they scale linearly in the number of asset transfers (you can't
|
||||
split/merge so the same unit is being transferred to a differing set of
|
||||
owners). Normal assets give a greater degree of flexibility, but scale worse
|
||||
as a single asset held might actually be the merging of several Taproot Asset
|
||||
UTXOs, thereby increasing proofs size as a function of the number of
|
||||
splits/merges in an asset's history. Pocket Universes are an off-chain transfer
|
||||
compression system that allows a consortium to stamp asset transfers that take
|
||||
place in an "imaginary" universe.
|
||||
|
||||
To further reduce validation costs, verifiers can choose to only verify a
|
||||
single input split all the way back to the genesis outpoint. This implements a
|
||||
naive form of probabilistic validation, as the probability that each unverified
|
||||
split is invalid decrease exponentially.
|
||||
|
||||
A Pocket Universe is similar to a commit chain. A single party, or a set of
|
||||
parties, commits to a set of transfers within the main chain, which themselves
|
||||
are anchored to an initial verifiable <code>genesisOutpoint</code>. A Pocket
|
||||
Universe is therefore a scaling tool, as with a single new commitment on-chain,
|
||||
an essentially unbounded amount of transfers can be timestamped within the
|
||||
chain. Pocket Universes may be useful in cases where a party has issued
|
||||
assets, that can only be used with the aide of the issuer, for example in-game
|
||||
assets. Although the Pocket Universe relies on a federation, unilateral exist
|
||||
is possible, given a proof of censorship event.
|
||||
|
||||
=====Pocket Universes Creation=====
|
||||
|
||||
In order to create a new empty Pocket Universe, the Pocket Universe
|
||||
orchestrator first creates a new unique tapscript commitment within a segwit v1
|
||||
output (Taproot) with the following structure:
|
||||
* <code>tagged_hash("TapLeaf", leaf_version || pocket_universe_marker || pocket_universe_version || pocket_universe_hash)</code>
|
||||
|
||||
where:
|
||||
* <code>pockt_universe_marker</code>: is the `sha256` hash of the ascii string "pocket universe".
|
||||
* <code>pocket_universe_version</code>: is the version of the Universe commitment used.
|
||||
* <code>pocket_universe_hash</code>: is the root hash of the Pocket Universe.
|
||||
** The Pocket Universe is a normal Taproot Asset MS-SMT with the exception that the referenced previous outpoints of the <code>prev_id</code> for each asset only exists within the Taproot Asset Virtual Transaction Graph.
|
||||
|
||||
This serves to create a new empty Pocket Universe, as the
|
||||
<code>pocket_universe_hash</code> will simply be the empty MS-SMT hash as no
|
||||
contents are currently present in the Pocket Universe.
|
||||
|
||||
The outpoint that commits to the creation of a Pocket Universe is hence
|
||||
referred to as the <code>pocketGenesisOutpoint</code>. A NUMS point derived
|
||||
from this outpoint can then be computed as <code>M =
|
||||
NUMS(pocketGenesisOutpoint)</code>. The traditional "hash and increment" approach to
|
||||
generating NUMS points can be used, or any other variant. As performance isn't
|
||||
a concern, the naive approach will likely be used in practice.
|
||||
|
||||
======Pocket Universe Dynamic Membership: Taproot Asset Virtual Transaction Graphs======
|
||||
|
||||
Within a Pocket Universe, rather than reference the on chain location of
|
||||
committed assets, a new virtual transaction graph is created, which is rooted
|
||||
at the <code>pocketGenesisOutpoint</code>. In order to join a Pocket Universe,
|
||||
an asset must first be suspended. Once suspended, they can be added to the
|
||||
Pocket Universe commitment, using the <code>pocketGenesisOutpoint</code> as a
|
||||
''new'' minting/issuance event. Subsequent transfers will then reference the
|
||||
''virtual transaction outpoint'' (as computed in the VM) as previous inputs.
|
||||
|
||||
Assets can also be minted ''directly'' into a Pocket Universe by the
|
||||
orchestrator. To do this, the orchestrator creates a normal genesis asset, but
|
||||
uses the normal all zero prev ID within the new Pocket Universe leaf.
|
||||
|
||||
======Joining a Pocket Universe======
|
||||
|
||||
In order to join a Pocket Universe, a party holding an asset `A` carries out
|
||||
the following steps:
|
||||
* In the same txn, send to the Pocket Universe NUMS key
|
||||
* Create a new entry in the Pocket Universe for that output
|
||||
* Within the new leaf, reference the pocket universe outpoint
|
||||
|
||||
Assets can be moved into a pocket Universe which is another commitment in the
|
||||
main Tapscript tree by "sending" the set of outpoints to a special NUMS asset
|
||||
key which is derived from the <code>genesisOutpoint</code> of the given asset.
|
||||
|
||||
|
||||
Once the assets have been from the PoV of the base Universe, a new parallel
|
||||
pocket Universe commitment can be created, which uses the ''new'' outpoint
|
||||
created as a result of the above transfer transaction as the very first
|
||||
spending input. From here, new transfers can be created, refreezing the
|
||||
created outpoints of the virtual Taproot Asset VM validation transaction. The
|
||||
result is an effective ''freezing'' of assets anchored in the main chain, which
|
||||
then permits them to be batched and transferred in the maintained Pocket
|
||||
Universe.
|
||||
|
||||
======Pocket Universe Transactions======
|
||||
|
||||
=======Leaving a Pocket Universe=======
|
||||
|
||||
====Asset Universe APIs & Federated Sync====
|
||||
|
||||
A Universe server communicates with clients and other Universe servers using
|
||||
the standard Universe API. As a Universe is a tree-based structure, it lends
|
||||
well to bisection based reconciliation protocols. A set of Universe servers can
|
||||
peer with each other to form a Universe Federation. A users submit issuance and
|
||||
transfer proofs to a sub-set of the Federation, gradual tree-based
|
||||
reconciliation will serve to eventually synchronize the new state across the
|
||||
set of federated Universe servers.
|
||||
|
||||
=====Universe gRPC API=====
|
||||
|
||||
The Universe gRPC API is implemented by the following standard gRPC service:
|
||||
|
||||
<source lang="python">
|
||||
service Universe {
|
||||
/*
|
||||
AssetRoots queries for the known Universe roots associated with each known
|
||||
asset. These roots represent the supply/audit state for each known asset.
|
||||
*/
|
||||
rpc AssetRoots (AssetRootRequest) returns (AssetRootResponse);
|
||||
|
||||
/*
|
||||
QueryAssetRoots attempts to locate the current Universe root for a specific
|
||||
asset. This asset can be identified by its asset ID or group key.
|
||||
*/
|
||||
rpc QueryAssetRoots (AssetRootQuery) returns (QueryRootResponse);
|
||||
|
||||
/*
|
||||
AssetLeafKeys queries for the set of Universe keys associated with a given
|
||||
asset_id or group_key. Each key takes the form: (outpoint, script_key),
|
||||
where outpoint is an outpoint in the Bitcoin blockchain that anchors a
|
||||
valid Taproot Asset commitment, and script_key is the script_key of the
|
||||
asset within the Taproot Asset commitment for the given asset_id or
|
||||
group_key.
|
||||
*/
|
||||
rpc AssetLeafKeys (ID) returns (AssetLeafKeyResponse);
|
||||
|
||||
/*
|
||||
AssetLeaves queries for the set of asset leaves (the values in the Universe
|
||||
MS-SMT tree) for a given asset_id or group_key. These represents either
|
||||
asset issuance events (they have a genesis witness) or asset transfers that
|
||||
took place on chain. The leaves contain a normal Taproot Asset asset proof,
|
||||
as well as details for the asset.
|
||||
*/
|
||||
rpc AssetLeaves (ID) returns (AssetLeafResponse);
|
||||
|
||||
/*
|
||||
QueryProof attempts to query for an issuance proof for a given asset based
|
||||
on its UniverseKey. A UniverseKey is composed of the Universe ID
|
||||
(asset_id/group_key) and also a leaf key (outpoint || script_key). If
|
||||
found, then the issuance proof is returned that includes an inclusion proof
|
||||
to the known Universe root, as well as a Taproot Asset state transition or
|
||||
issuance proof for the said asset.
|
||||
*/
|
||||
rpc QueryProof (UniverseKey) returns (AssetProofResponse);
|
||||
|
||||
/*
|
||||
InsertProof attempts to insert a new issuance proof into the
|
||||
Universe tree specified by the UniverseKey. If valid, then the proof is
|
||||
inserted into the database, with a new Universe root returned for the
|
||||
updated asset_id/group_key.
|
||||
*/
|
||||
rpc InsertProof (AssetProof) returns (AssetProofResponse);
|
||||
}
|
||||
</source>
|
||||
|
||||
The service allows users to fetch the complete set of asset roots, fetch the
|
||||
Universe root for a given asset, fetch the set of leaves/keys, and also attempt
|
||||
to add a new issuance/transfer proof to the target Universe server.
|
||||
|
||||
The definition of each of the proto messages follows:
|
||||
<source lang="python">
|
||||
message AssetRootRequest {}
|
||||
|
||||
message MerkleSumNode {
|
||||
// The MS-SMT root hash for the branch node.
|
||||
bytes root_hash = 1;
|
||||
|
||||
// The root sum of the branch node. This is hashed to create the root_hash
|
||||
// along with the left and right siblings. This value represents the total
|
||||
// known supply of the asset.
|
||||
int64 root_sum = 2;
|
||||
}
|
||||
|
||||
message ID {
|
||||
oneof id {
|
||||
// The 32-byte asset ID.
|
||||
bytes asset_id = 1;
|
||||
|
||||
// The 32-byte asset ID encoded as a hex string.
|
||||
string asset_id_str = 2;
|
||||
|
||||
// The 32-byte asset group key.
|
||||
bytes group_key = 3;
|
||||
|
||||
// The 32-byte asset group key encoded as hex string.
|
||||
string group_key_str = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message UniverseRoot {
|
||||
ID id = 1;
|
||||
|
||||
// The merkle sum sparse merkle tree root associated with the above
|
||||
// universe ID.
|
||||
MerkleSumNode mssmt_root = 3;
|
||||
}
|
||||
|
||||
message AssetRootResponse {
|
||||
// A map of the set of known universe roots for each asset. The key in the
|
||||
// map is the 32-byte asset_id or group key hash.
|
||||
map<string, UniverseRoot> universe_roots = 1;
|
||||
}
|
||||
|
||||
message AssetRootQuery {
|
||||
// An ID value to uniquely identify a Universe root.
|
||||
ID id = 1;
|
||||
}
|
||||
|
||||
message QueryRootResponse {
|
||||
// The asset root for the given asset ID or group key.
|
||||
UniverseRoot asset_root = 1;
|
||||
}
|
||||
|
||||
message Outpoint {
|
||||
// The output as a hex encoded (and reversed!) string.
|
||||
string hash_str = 1;
|
||||
|
||||
// The index of the output.
|
||||
int32 index = 2;
|
||||
}
|
||||
|
||||
message AssetKey {
|
||||
// The outpoint of the asset key, either as a single hex encoded string, or
|
||||
// an unrolled outpoint.
|
||||
oneof outpoint {
|
||||
string op_str = 1;
|
||||
|
||||
Outpoint op = 2;
|
||||
}
|
||||
|
||||
// The script key of the asset.
|
||||
oneof script_key {
|
||||
bytes script_key_bytes = 3;
|
||||
|
||||
string script_key_str = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message AssetLeafKeyResponse {
|
||||
// The set of asset leaf keys for the given asset ID or group key.
|
||||
repeated AssetKey asset_keys = 1;
|
||||
}
|
||||
|
||||
message AssetLeaf {
|
||||
// The asset included in the leaf.
|
||||
taprpc.Asset asset = 1;
|
||||
|
||||
// TODO(roasbeef): only needed for display? can get from proof below ^
|
||||
|
||||
// The asset issuance proof, which proves that the asset specified above
|
||||
// was issued properly.
|
||||
bytes issuance_proof = 2;
|
||||
}
|
||||
|
||||
message AssetLeafResponse {
|
||||
// The set of asset leaves for the given asset ID or group key.
|
||||
repeated AssetLeaf leaves = 1;
|
||||
}
|
||||
|
||||
message UniverseKey {
|
||||
// The ID of the asset to query for.
|
||||
ID id = 1;
|
||||
|
||||
// The asset key to query for.
|
||||
AssetKey leaf_key = 2;
|
||||
}
|
||||
|
||||
message AssetProofResponse {
|
||||
// The request original request for the issuance proof.
|
||||
UniverseKey req = 1;
|
||||
|
||||
// The Universe root that includes this asset leaf.
|
||||
UniverseRoot universe_root = 2;
|
||||
|
||||
// An inclusion proof for the asset leaf included below. The value is that
|
||||
// issuance proof itself, with a sum value of the amount of the asset.
|
||||
bytes universe_inclusion_proof = 3;
|
||||
|
||||
// The asset leaf itself, which includes the asset and the issuance proof.
|
||||
AssetLeaf asset_leaf = 4;
|
||||
}
|
||||
|
||||
message AssetProof {
|
||||
// The ID of the asset to insert the proof for.
|
||||
UniverseKey key = 1;
|
||||
|
||||
// The asset leaf to insert into the Universe tree.
|
||||
AssetLeaf asset_leaf = 4;
|
||||
}
|
||||
|
||||
enum UniverseSyncMode {
|
||||
// A sync node that indicates that only new asset creation (minting) proofs
|
||||
// should be synced.
|
||||
SYNC_ISSUANCE_ONLY = 0;
|
||||
|
||||
// A syncing mode that indicates that all asset proofs should be synced.
|
||||
// This includes normal transfers as well.
|
||||
SYNC_FULL = 1;
|
||||
}
|
||||
|
||||
message SyncTarget {
|
||||
ID id = 1;
|
||||
}
|
||||
|
||||
message SyncRequest {
|
||||
string universe_host = 1;
|
||||
|
||||
// The sync mode. This determines what type of proofs are synced.
|
||||
UniverseSyncMode sync_mode = 2;
|
||||
|
||||
// The set of assets to sync. If none are specified, then all assets are
|
||||
// synced.
|
||||
repeated SyncTarget sync_targets = 3;
|
||||
}
|
||||
|
||||
message SyncedUniverse {
|
||||
// The old Universe root for the synced asset.
|
||||
UniverseRoot old_asset_root = 1;
|
||||
|
||||
// The new Universe root for the synced asset.
|
||||
UniverseRoot new_asset_root = 2;
|
||||
|
||||
// The set of new asset leaves that were synced.
|
||||
repeated AssetLeaf new_asset_leaves = 3;
|
||||
}
|
||||
|
||||
message SyncResponse {
|
||||
// The set of synced asset Universes.
|
||||
repeated SyncedUniverse synced_universes = 1;
|
||||
}
|
||||
</source>
|
||||
|
||||
|
||||
=====Universe REST API=====
|
||||
|
||||
In addition to a gRPC API, Universe servers also observe a matching REST API.
|
||||
The REST API is the mirror of the gRPC API, and is structured to enable
|
||||
familiar access to Universe information as one would expect in a block
|
||||
explorer.
|
||||
|
||||
The following yaml describes the REST interface for Universe servers:
|
||||
<source lang="yaml">
|
||||
type: google.api.Service
|
||||
config_version: 3
|
||||
|
||||
http:
|
||||
rules:
|
||||
- selector: universerpc.Universe.AssetRoots
|
||||
get: "/v1/taproot-assets/universe/roots"
|
||||
|
||||
- selector: universerpc.Universe.QueryAssetRoots
|
||||
get: "/v1/taproot-assets/universe/roots/asset-id/{id.asset_id_str}"
|
||||
|
||||
- selector: universerpc.Universe.QueryAssetRoots
|
||||
get: "/v1/taproot-assets/universe/roots/group-key/{id.group_key_str}"
|
||||
|
||||
- selector: universerpc.Universe.AssetLeafKeys
|
||||
get: "/v1/taproot-assets/universe/keys/asset-id/{asset_id_str}"
|
||||
|
||||
- selector: universerpc.Universe.AssetLeafKeys
|
||||
get: "/v1/taproot-assets/universe/keys/group-key/{group_key_str}"
|
||||
|
||||
- selector: universerpc.Universe.AssetLeaves
|
||||
get: "/v1/taproot-assets/universe/leaves/asset-id/{asset_id_str}"
|
||||
|
||||
- selector: universerpc.Universe.AssetLeaves
|
||||
get: "/v1/taproot-assets/universe/leaves/group-key/{group_key_str}"
|
||||
|
||||
- selector: universerpc.Universe.QueryProof
|
||||
get: "/v1/taproot-assets/universe/proofs/asset-id/{id.asset_id_str}/{leaf_key.op.hash_str}/{leaf_key.op.index}/{leaf_key.script_key_str}"
|
||||
|
||||
- selector: universerpc.Universe.QueryProof
|
||||
get: "/v1/taproot-assets/universe/proofs/group-key/{id.group_key_str}/{leaf_key.op.hash_str}/{leaf_key.op.index}/{leaf_key.script_key_str}"
|
||||
|
||||
- selector: universerpc.Universe.InsertProof
|
||||
post: "/v1/taproot-assets/universe/proofs/asset-id/{key.id.asset_id_str}/{key.leaf_key.op.hash_str}/{key.leaf_key.op.index}/{key.leaf_key.script_key_str}"
|
||||
body: "*"
|
||||
|
||||
- selector: universerpc.Universe.InsertProof
|
||||
post: "/v1/taproot-assets/universe/proofs/group-key/{key.id.group_key_str}/{key.leaf_key.op.hash_str}/{key.leaf_key.op.index}/{key.leaf_key.script_key_str}"
|
||||
body: "*"
|
||||
|
||||
- selector: universerpc.Universe.SyncUniverse
|
||||
post: "/v1/taproot-assets/universe/sync"
|
||||
body: "*"
|
||||
</source>
|
||||
|
||||
As an example, in order to query for any issued assets residing at the outpoint
|
||||
`txid:vout`, for an assetiD `x` a user can hit the following endpoint:
|
||||
<code>
|
||||
/v1/taproot-assets/universe/keys/asset-id/x/txid/vout
|
||||
</code>
|
||||
|
||||
|
||||
=====Simple Universe Sync=====
|
||||
|
||||
As mentioned above, the tree based structure of a Universe server lends easily
|
||||
to bisection based set reconciliation. In this case, the keys comprise the set
|
||||
being synchronized.
|
||||
|
||||
In this section, we describe a simple linear algorithm for syncing a local
|
||||
Universe, with a remote Universe server:
|
||||
|
||||
<source lang="python">
|
||||
sync_with_universe(local_universe: UniverseServer, remote_universe: UniverseServer) -> None
|
||||
// First fetch the set of roots from the local + remote server.
|
||||
local_roots = local_universe.asset_roots()
|
||||
remote_roots = remote_universe.asset_roots()
|
||||
|
||||
// If the local roots match the remote roots, then we're done.
|
||||
if local_roots == remote_roots:
|
||||
return
|
||||
|
||||
// Otherwise, for each root, we'll figure out which leaves we're missing.
|
||||
for i, remote_root in range(remote_roots):
|
||||
if remote_roots == local_roots[i]:
|
||||
continue
|
||||
|
||||
remote_asset_keys = remote_universe.asset_leaf_keys(remote_root.id)
|
||||
local_asset_keys = local_universe.asset_leaf_keys(local_root.id)
|
||||
|
||||
missing_keys = set(remote_asset_keys) - set(local_asset_keys)
|
||||
|
||||
for missing_key in range missing_keys:
|
||||
missing_leaf = remote_universe.query_issuance_proofs(missing_key)
|
||||
|
||||
local_universe.insert_issuance_proof(missing_leaf)
|
||||
</source>
|
||||
|
||||
A simple sync can be augmented by first recursively fetching the mismatched
|
||||
sibling until an acceptable depth is reached before fetching all the leaves in
|
||||
the terminal sub-tree. Each step serves to cut in half the total number of keys
|
||||
that need to be sent in order to reconcile state.
|
||||
|
||||
==Test Vectors==
|
||||
|
||||
TBD
|
||||
|
||||
==Backwards Compatibility==
|
||||
|
||||
==Reference Implementation==
|
||||
|
||||
github.com/lightninglabs/taproot-assets/universe
|
288
bip-tap-vm.mediawiki
Normal file
288
bip-tap-vm.mediawiki
Normal file
|
@ -0,0 +1,288 @@
|
|||
<pre>
|
||||
BIP: ???
|
||||
Layer: Applications
|
||||
Title: Taproot Asset Script v1
|
||||
Author: Olaoluwa Osuntokun <laolu32@gmail.com>
|
||||
Comments-Summary: No comments yet.
|
||||
Comments-URI: https://git
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Created: 2021-12-10
|
||||
License: BSD-2-Clause
|
||||
</pre>
|
||||
|
||||
==Abstract==
|
||||
|
||||
This document describes the virtual machine execution environment used to
|
||||
validate Taproot Asset transfers that utilize an
|
||||
<code>asset_script_version</code> of 1.
|
||||
The execution environment described in this document is a slight twist on
|
||||
the taproot validation rules defined in BIPs 341 and 342. Given a Taproot Asset
|
||||
one or more Taproot Asset leaves to be spent (inputs) and asset leaves to be
|
||||
created, a "virtual" taproot Bitcoin transaction is created. This transaction
|
||||
is a 1-input-1-output transaction that commits to the inputs and output set
|
||||
using a merkle sum tree. With this mapping complete, validation takes place as
|
||||
normal.
|
||||
|
||||
==Copyright==
|
||||
|
||||
This document is licensed under the 2-clause BSD license.
|
||||
|
||||
==Motivation==
|
||||
|
||||
The Taproot Asset overlay permits the usage of a nearly arbitrary virtual machine
|
||||
for validation of transfers within the system. In order to reduce the scope of
|
||||
the initial version of the protocol, we describe a way to leverage the existing
|
||||
Bitcoin Script virtual machine, allowing us to inherit a baseline set of
|
||||
expressibility, while allowing implementers re-use existing tools and
|
||||
libraries.
|
||||
|
||||
==Design==
|
||||
|
||||
The Taproot Asset <code>asset_script_version</code> 1 maps a Taproot Asset input
|
||||
and output set to a "virtual" Bitcoin transaction.
|
||||
The input and output sets are committed to within a single 1-input-1-output
|
||||
transaction using a normal merkle sum tree
|
||||
(TODO(roasbeef): non-inclusion useful at all here??).
|
||||
Via the merkle-sum
|
||||
invariant of the augmented merkle tree, a validator is able to enforce
|
||||
non-inflation of assets by asserting that the committed input sum is ''equal''
|
||||
to the committed output sum. Once this invariant is verified, execution resumes
|
||||
as normal using the BIP 341+342 validation rules, with additional pre-execution
|
||||
checks that may fail validation early.
|
||||
|
||||
===Specification===
|
||||
|
||||
A single 1-input-1-output transaction is used to compress the Taproot Asset
|
||||
state transition state into a constant size transaction. Given a Taproot Asset
|
||||
commitment (which lives in a taproot output), and its valid opening, the set
|
||||
the previous asset ID are compressed into a single input, and the present
|
||||
<code>split_commitment</code> is used to compress the output state.
|
||||
|
||||
State transition validation may take one or multiple asset leaves within a
|
||||
single transaction (with the leaves living in different outputs). When a single
|
||||
leaf is present, no splits occurred in the state transition, or the asset is a
|
||||
collectible. When two or more leaves are specified, then all but one of the
|
||||
leaves were splits resulting from a split event at the Taproot Asset layer. In
|
||||
this case, the split commitment proof, as well as the validity of the state
|
||||
transition creating the splits are validated.
|
||||
|
||||
|
||||
====Mapping Inputs====
|
||||
|
||||
Input mapping is only executed for state transitions that specify
|
||||
<code>prev_asset_witnesses</code>.
|
||||
|
||||
Given a set of inputs, each identified by a <code>prev_asset_id</code>, the
|
||||
input commitment (which is used as the previous output) is constructed as
|
||||
follows:
|
||||
|
||||
# Initialize a new empty MS-SMT tree as specified in [[./bip-tap-ms-smt.mediawiki|bip-tap-ms-smt]].
|
||||
# For each Taproot Asset input ''c_i'', identified in the <code>prev_asset_witnesses</code> field:
|
||||
## If the asset input has a <code>split_commitment</code> in the witness, that needs to be removed before the serialization step.
|
||||
## Serialize the referenced previous asset leaf (identified by <code>prev_outpoint || asset_id || asset_script_hash</code>) in TLV format.
|
||||
## Insert this leaf into the MS-SMT tree, with a key of the <code>prev_id_identifier</code>, a value of the serialized leaf, and sum value of the asset amount contained in the leaf.
|
||||
# Obtain the root hash <code>input_root</code> and sum value <code>input_asset_sum</code> resulting from the tree creation and root digest computation.
|
||||
# Let the hash of the serialized 36-byte MS-SMT root be the sole previous outpoint (the txid) of the virtual execution transaction.
|
||||
|
||||
With the above routine, we map the input set into a MS-SMT tree, which also
|
||||
commits to the total amount being spent of any given asset. During
|
||||
verification, as there may be multiple input witnesses, during validation, the
|
||||
<code>asset_witness</code> for each input is used as the initial witness stack.
|
||||
|
||||
Notice that we don't map the <code>relative_lock_time</code> field here within
|
||||
this unified input commitment. Instead we'll map this during the
|
||||
verification/signing process, which enables the existence of per-input relative
|
||||
and absolute lock time.
|
||||
|
||||
The following algorithm implements the input mapping required for full state
|
||||
transition verification:
|
||||
<source lang="python">
|
||||
make_virtual_input(prev_inputs: map[PrevOut]TaprootAssetLeaf) -> (MerkleSumRoot, TxIn):
|
||||
input_smt = new_ms_smt()
|
||||
|
||||
for prev_out, taproot_asset_leaf in prev_inputs:
|
||||
leaf_bytes = taproot_asset_leaf.serialize_tlv()
|
||||
|
||||
input_smt.insert(key=prev_out, value=leaf_bytes, sum_value=taproot_asset_leaf.amt)
|
||||
|
||||
input_root = input_smt.root()
|
||||
|
||||
virtual_txid = sha256(input_root.hash || input_root.sum_value)
|
||||
|
||||
# We only only bind the virtual txid here. Below we'll modify the input
|
||||
# index based on the ordering of this SMT.
|
||||
return input_root, NewTxIn(NewOutPoint(txid=virtual_txid), nil)
|
||||
|
||||
</source>
|
||||
|
||||
====Mapping Outputs====
|
||||
|
||||
Output mapping is only executed for state transitions that specify
|
||||
<code>prev_asset_witnesses</code>.
|
||||
|
||||
Given a Taproot Asset output, and any associated outputs contained within its
|
||||
<code>split_commitment_root</code>, the output commitment is constructed as
|
||||
follows:
|
||||
|
||||
# For normal asset transfers:
|
||||
## Let the output value be the sum of all the <code>amt</code> fields on the top level as well as the split commitment cohort set, in other words the last 4-bytes of the <code>split_commitment_root</code>.
|
||||
## Let the output script be the first 32-bytes of the <code>split_commitment_root</code> value converted to a segwit v1 witness program (taproot).
|
||||
|
||||
# For collectible asset transfers
|
||||
## Let the output value be exactly ''1'' (as each TLV leaf related to a collectible can only ever transfer that same collectible to another leaf).
|
||||
## Let the output script be the first 32-bytes of an MS-SMT tree with a single element of the serialized TLV leaf of the collectible.
|
||||
### The key for this single value is <code>sha256(asset_key_family || asset_id || asset_script_key)</code>. If a <code>asset_key_family</code> field isn't specified, then 32-bytes of zeroes should be used in place.
|
||||
|
||||
The following algorithm implements the output mapping required for full state
|
||||
transition verification:
|
||||
<source lang="python">
|
||||
make_virtual_txout(leaf: TaprootAssetLeaf) -> (MerkleSumRoot, TxOut):
|
||||
match leaf.asset_type:
|
||||
case Normal:
|
||||
tx_out = NewTxOut(
|
||||
pk_script=[OP_1 OP_DATA_32 leaf.split_commitment_root.hash],
|
||||
value=leaf.split_commitment_root.sum_value,
|
||||
)
|
||||
|
||||
return leaf.split_commitment_root, tx_out
|
||||
|
||||
case Collectible:
|
||||
output_smt = new_ms_smt()
|
||||
output_smt.insert(
|
||||
key=sha256(leaf.asset_key_family || leaf.asset_id || leaf.asset_script_key)
|
||||
value=leaf.serialize_tlv(),
|
||||
sum_value=1,
|
||||
)
|
||||
|
||||
witness_program = output_smt.root_hash()
|
||||
|
||||
tx_out = NewTxOut(
|
||||
pk_script=[OP_1 OP_DATA_32 witness_program],
|
||||
value=1,
|
||||
)
|
||||
|
||||
return output_smt.root, tx_out
|
||||
</source>
|
||||
|
||||
====Validating a State Transition====
|
||||
|
||||
If a state transition specifies a <code>prev_asset_witnesses</code> field, then
|
||||
once the set of inputs and outputs have been mapped to our virtual Bitcoin
|
||||
transaction (creating a v2 Bitcoin transaction with a single input and output),
|
||||
validation proceeds as normal according to BIP 341+342 with the following
|
||||
modifications:
|
||||
|
||||
# If the <code>input_asset_sum</code> is not exactly equal to the <code>output_asset_sum</code> validation MUST fail.
|
||||
# For each <code>prev_input</code> within the set of referenced <code>prev_asset_witnesses</code>:
|
||||
## If the <code>asset_type</code> of the referenced input leaf doesn't map the <code>asset_type</code> of the Taproot Asset leaf spending the input, validation MUST fail.
|
||||
## Construct a single-input-single-output Bitcoin transaction based on the input and output mapping above.
|
||||
### The prev out input index should be the lexicographical index of the <code>prev_id_identifier</code> field for each input.
|
||||
### The previous public key script should be the <code>asset_script_hash</code> for the current previous input, mapped to a v1 segwit witness program (taproot).
|
||||
### The input value for each included input is to be the <code>amt</code> field of the previous Taproot Asset output being spent.
|
||||
### Set the sequence number to the <code>relative_lock_time</code> field of the input, if it exists.
|
||||
## Set the lock time of the transaction as the <code>lock_time</code> of the input TLV leaf being validated, if it exists.
|
||||
## All signatures included in the witness MUST be exactly 64-bytes in length, which triggers <code>SIGHASH_DEFAULT</code> evaluation.
|
||||
## If the <code>prev_asset_id</code> is blank, then ALL witnesses MUST be blank as well and the <code>prev_outpoint</code> values as well. In this case, verification succeeds as this is only a creation/minting transaction.
|
||||
## If the <code>asset_id</code> value is NOT the same for each Taproot Asset input and output, validation MUST fail.
|
||||
### Alternatively, assert that each input and output references the same <code>asset_family_key</code> field.
|
||||
## Perform external lock time and relative lock time validation:
|
||||
### If a <code>relative_lock_time</code> field exists, if the input age of the referenced TLV leaf is less than <code>relative_lock_time</code> validation MUST fail.
|
||||
### If a <code>lock_time</code> field exists, if the block height of the block that includes the transaction is less than <code>lock_time</code> validation MUST fail.
|
||||
## Validate the transaction according to the BIP 341+342 rules.
|
||||
|
||||
We explicitly implement lock time semantics at this level, as the sequence and
|
||||
lock time fields in the context of Bitcoin itself are validated from the PoV of
|
||||
connecting a new block to the end of the main chain.
|
||||
|
||||
Otherwise, if a state transition only specifies a <code>split_commitment_proof</code>, then:
|
||||
# If the Taproot Asset output to be validated only specifies a <code>split_commitment_proof</code> and no explicit inputs, then a valid inclusion proof for the output MUST be presented and valid.
|
||||
## If the proof is invalid, then validation MUST fail.
|
||||
# Given the "parent" split, execute the input+output mapping and verify the state transition using the logic above.
|
||||
|
||||
The following algorithm implements verification for top level Taproot Asset
|
||||
leaves, as well leaves created via split commitments:
|
||||
<source lang="python">
|
||||
verify_taproot_asset_state_transition(leaf: TaprootAssetLeaf, leaf_split: TaprootAssetLeaf) -> bool
|
||||
if is_valid_issuance_txn(leaf):
|
||||
return true
|
||||
|
||||
if leaf_split is not None:
|
||||
if leaf is None:
|
||||
return false
|
||||
|
||||
if !verify_split_commitment(leaf.split_commitment_root,
|
||||
leaf_split.split_commitment_proof):
|
||||
|
||||
return false
|
||||
|
||||
input_smt, tx_in = make_virtual_input(leaf.prev_inputs)
|
||||
output_smt, tx_out = make_virtual_txout(leaf)
|
||||
|
||||
if input_smt.sum_value != output_smt.sum_value:
|
||||
return false
|
||||
|
||||
virtual_tx_template = NewTx([tx_in], [tx_out])
|
||||
for input in range leaf.prev_inputs:
|
||||
if input.asset_type != leaf.asset_type:
|
||||
return false
|
||||
|
||||
match input.asset_id:
|
||||
case AssetID:
|
||||
if input.asset_id != leaf.asset_id:
|
||||
return false
|
||||
case KeyFamily:
|
||||
if input.asset_key_family != leaf.asset_key_family:
|
||||
return false
|
||||
|
||||
virtual_tx = virtual_tx_template.clone()
|
||||
|
||||
if !parse_valid_schnorr_sigs(input.asset_witness):
|
||||
return false
|
||||
|
||||
virtual_tx.tx_in[0].witness = input.asset_witness
|
||||
virtual_tx.tx_in[0].prev_out.index = input_smt.leaf_index_of(input)
|
||||
|
||||
prev_pk_script = OP_1 OP_DATA_32 input.asset_script_key
|
||||
input_value = input.amt
|
||||
|
||||
if input.relative_lock_time != 0:
|
||||
virtual_tx.tx_in[0].sequence = relative_lock_time
|
||||
|
||||
input_age = conf_input_age(input)
|
||||
if num_confs(input) < input_age:
|
||||
return false
|
||||
|
||||
if input.lock_time != 0:
|
||||
virtual_tx.lock_time = leaf.lock_time
|
||||
|
||||
block_height = env.block_height()
|
||||
if block_height < virtual_tx.lock_time:
|
||||
return false
|
||||
|
||||
vm = new_script_vm(
|
||||
prev_pk_script=prev_pk_script, tx=virtual_tx, input_index=0,
|
||||
input_amt=input_value,
|
||||
)
|
||||
|
||||
if !vm.Execute():
|
||||
return false
|
||||
|
||||
return true
|
||||
</source>
|
||||
|
||||
==Test Vectors==
|
||||
|
||||
Test vectors for [[Validating a State Transition]] can be found here:
|
||||
* [[bip-tap-vm/vm_validation_generated.json|VM validation test vectors]]
|
||||
* [[bip-tap-vm/vm_validation_generated_error_cases.json|VM validation error test vectors]]
|
||||
|
||||
The test vectors are automatically generated by
|
||||
[https://github.com/lightninglabs/taproot-assets/tree/main/vm unit tests in
|
||||
the Taproot Assets GitHub repository].
|
||||
|
||||
==Backwards Compatibility==
|
||||
|
||||
==Reference Implementation==
|
||||
|
||||
github.com/lightninglabs/taproot-assets/tree/main/vm
|
1970
bip-tap-vm/vm_validation_generated.json
Normal file
1970
bip-tap-vm/vm_validation_generated.json
Normal file
File diff suppressed because it is too large
Load diff
1458
bip-tap-vm/vm_validation_generated_error_cases.json
Normal file
1458
bip-tap-vm/vm_validation_generated_error_cases.json
Normal file
File diff suppressed because it is too large
Load diff
1117
bip-tap.mediawiki
Normal file
1117
bip-tap.mediawiki
Normal file
File diff suppressed because it is too large
Load diff
31
bip-tap/asset_burn_key_generated.json
Normal file
31
bip-tap/asset_burn_key_generated.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"valid_test_cases": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"expected": "b87da731321c9e90a2f3d525cf81a2f503e04ea49543692951e6b88752a0d72d",
|
||||
"comment": "empty prev ID"
|
||||
},
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "00000000000000000000000000000000000000000000000000000000aa998877:123",
|
||||
"asset_id": "0102030400000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "020304050000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"expected": "77493dcf8c7e6c1f214824409b2468afe8e4e5faa47e6ae87ddb60226ad4edde",
|
||||
"comment": "dummy value ID"
|
||||
},
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "c8ca462e6247b1c7d67f9e2b5e371fc9303c3c3e6d690e8fb4a6bb5ca5b78104:354062834",
|
||||
"asset_id": "560982cea2defb7795dda938422b4d7ae5462e64cde32fc68ced4f503f8a5af7",
|
||||
"script_key": "03c50bfc65dfb20e9b9c1c6d8b435ef91f41eb86434576823eeaf3a69fa7e1fc78"
|
||||
},
|
||||
"expected": "a76bc68f430c78cfdad6d72abf143de10c8b679842fe00736072361b52ad426c",
|
||||
"comment": "random value ID"
|
||||
}
|
||||
]
|
||||
}
|
45
bip-tap/asset_tlv_encoding_error_cases.json
Normal file
45
bip-tap/asset_tlv_encoding_error_cases.json
Normal file
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"error_test_cases": [
|
||||
{
|
||||
"asset": {},
|
||||
"error": "missing genesis fields"
|
||||
},
|
||||
{
|
||||
"asset": {
|
||||
"genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"error": "missing script key"
|
||||
},
|
||||
{
|
||||
"asset": {
|
||||
"genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"error": "invalid script key length",
|
||||
"comment": "script key must be 33 bytes (compressed)"
|
||||
},
|
||||
{
|
||||
"asset": {
|
||||
"genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"group_key": {}
|
||||
},
|
||||
"error": "missing group key"
|
||||
},
|
||||
{
|
||||
"asset": {
|
||||
"genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"group_key": {
|
||||
"group_key": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"error": "invalid group key length",
|
||||
"comment": "group key must be 33 bytes (compressed)"
|
||||
}
|
||||
]
|
||||
}
|
142
bip-tap/asset_tlv_encoding_generated.json
Normal file
142
bip-tap/asset_tlv_encoding_generated.json
Normal file
|
@ -0,0 +1,142 @@
|
|||
{
|
||||
"valid_test_cases": [
|
||||
{
|
||||
"asset": {
|
||||
"version": 1,
|
||||
"genesis_first_prev_out": "0101010101010101010101010101010101010101010101010101010101010101:1",
|
||||
"genesis_tag": "asset",
|
||||
"genesis_meta_hash": "0102030000000000000000000000000000000000000000000000000000000000",
|
||||
"genesis_output_index": 1,
|
||||
"genesis_type": 1,
|
||||
"amount": 1,
|
||||
"lock_time": 1337,
|
||||
"relative_lock_time": 6,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0101010101010101010101010101010101010101010101010101010101010101:1",
|
||||
"asset_id": "0101010101010101010101010101010101010101010101010101010101010101",
|
||||
"script_key": "03a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": {
|
||||
"proof": "000197efb64d447880bacc7070f428a1310b2592d155b752da382934d4bd0fbb419a000000000000000affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"root_asset": {
|
||||
"version": 1,
|
||||
"genesis_first_prev_out": "0101010101010101010101010101010101010101010101010101010101010101:1",
|
||||
"genesis_tag": "asset",
|
||||
"genesis_meta_hash": "0102030000000000000000000000000000000000000000000000000000000000",
|
||||
"genesis_output_index": 1,
|
||||
"genesis_type": 1,
|
||||
"amount": 1,
|
||||
"lock_time": 1337,
|
||||
"relative_lock_time": 6,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0202020202020202020202020202020202020202020202020202020202020202:2",
|
||||
"asset_id": "0202020202020202020202020202020202020202020202020202020202020202",
|
||||
"script_key": "03a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f"
|
||||
},
|
||||
"tx_witness": [
|
||||
"02",
|
||||
"02"
|
||||
],
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": {
|
||||
"hash": "0101010101010101010101010101010101010101010101010101010101010101",
|
||||
"sum": "1337"
|
||||
},
|
||||
"script_version": 1,
|
||||
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"group_key": {
|
||||
"group_key": "03a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"group_key_sig": "e907831f80848d1069a5371b402410364bdf1c5f8307b0084c55f1ce2dca821525f66a4a85ea8b71e482a74f382d2ce5ebeee8fdb2172f477df4900d310536c0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 1,
|
||||
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"group_key": {
|
||||
"group_key": "03a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"group_key_sig": "e907831f80848d1069a5371b402410364bdf1c5f8307b0084c55f1ce2dca821525f66a4a85ea8b71e482a74f382d2ce5ebeee8fdb2172f477df4900d310536c0"
|
||||
}
|
||||
},
|
||||
"expected": "000101014f010101010101010101010101010101010101010101010101010101010101010100000001056173736574010203000000000000000000000000000000000000000000000000000000000000000001010201010301010403fd053905010606fd024501fd02410065010101010101010101010101010101010101010101010101010101010101010100000001010101010101010101010101010101010101010101010101010101010101010103a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f02fd01d64a000197efb64d447880bacc7070f428a1310b2592d155b752da382934d4bd0fbb419a000000000000000affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffd0188000101014f010101010101010101010101010101010101010101010101010101010101010100000001056173736574010203000000000000000000000000000000000000000000000000000000000000000001010201010301010403fd05390501060670016e0065020202020202020202020202020202020202020202020202020202020202020200000002020202020202020202020202020202020202020202020202020202020202020203a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f0105020102010207280101010101010101010101010101010101010101010101010101010101010101000000000000053908020001092102a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f0a6103a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078fe907831f80848d1069a5371b402410364bdf1c5f8307b0084c55f1ce2dca821525f66a4a85ea8b71e482a74f382d2ce5ebeee8fdb2172f477df4900d310536c008020001092102a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f0a6103a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078fe907831f80848d1069a5371b402410364bdf1c5f8307b0084c55f1ce2dca821525f66a4a85ea8b71e482a74f382d2ce5ebeee8fdb2172f477df4900d310536c0",
|
||||
"comment": "random split asset with root asset"
|
||||
},
|
||||
{
|
||||
"asset": {
|
||||
"version": 2,
|
||||
"genesis_first_prev_out": "0202020202020202020202020202020202020202020202020202020202020202:2",
|
||||
"genesis_tag": "asset",
|
||||
"genesis_meta_hash": "0102030000000000000000000000000000000000000000000000000000000000",
|
||||
"genesis_output_index": 2,
|
||||
"genesis_type": 2,
|
||||
"amount": 2,
|
||||
"lock_time": 1337,
|
||||
"relative_lock_time": 6,
|
||||
"prev_witnesses": [
|
||||
{
|
||||
"prev_id": null,
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
},
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"asset_id": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"script_key": "000000000000000000000000000000000000000000000000000000000000000000"
|
||||
},
|
||||
"tx_witness": null,
|
||||
"split_commitment": null
|
||||
},
|
||||
{
|
||||
"prev_id": {
|
||||
"out_point": "0202020202020202020202020202020202020202020202020202020202020202:2",
|
||||
"asset_id": "0202020202020202020202020202020202020202020202020202020202020202",
|
||||
"script_key": "03a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f"
|
||||
},
|
||||
"tx_witness": [
|
||||
"02",
|
||||
"02"
|
||||
],
|
||||
"split_commitment": null
|
||||
}
|
||||
],
|
||||
"split_commitment_root": null,
|
||||
"script_version": 2,
|
||||
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"group_key": null
|
||||
},
|
||||
"expected": "000102014f020202020202020202020202020202020202020202020202020202020202020200000002056173736574010203000000000000000000000000000000000000000000000000000000000000000002020201020301020403fd053905010606d9030067006500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e0065020202020202020202020202020202020202020202020202020202020202020200000002020202020202020202020202020202020202020202020202020202020202020203a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f0105020102010208020002092102a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"comment": "random asset with multiple previous witnesses"
|
||||
},
|
||||
{
|
||||
"asset": {
|
||||
"version": 0,
|
||||
"genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0",
|
||||
"genesis_tag": "",
|
||||
"genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"genesis_output_index": 0,
|
||||
"genesis_type": 0,
|
||||
"amount": 0,
|
||||
"lock_time": 0,
|
||||
"relative_lock_time": 0,
|
||||
"prev_witnesses": null,
|
||||
"split_commitment_root": null,
|
||||
"script_version": 0,
|
||||
"script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"group_key": null
|
||||
},
|
||||
"expected": "000100014a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002010003010008020000092102a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f",
|
||||
"comment": "minimal asset"
|
||||
}
|
||||
],
|
||||
"error_test_cases": null
|
||||
}
|
Loading…
Add table
Reference in a new issue