catchup: into main from long_lived/post_1.5.0 @ 916ccee549 (#12629)

* updated wallet name

* deprecated series

* swap to cat2

* updating .gitmodule to point to defender-gui

* Remove break (its preventing other sockets from getting data when earlier ones have an error) (#12241)

* Convert DID Wallet to use the new coin selection algorithm that the normal wallet and the CAT wallet already use (#12063)

* small type change

* use coin_selection.py with DID Wallet

use more efficient coin selection methods.

* Add special DID edgecase + fix int type

* Ms.fix coin selection (#12261)

* Fix coin selection bug

* Fix properly

* Fallback in cases of too many coins selected

* Also check for num coins

* Lint issues.

* Add another test

* No sorting, and faster knapsack

* Lint fix

* Remove comment and useless check

* Lint line

* Tx submission idempotance, and prioritize wallet (#12282)

* Tx submission idempotance, and prioritize wallet

* TODO comment

* Updating gui modules

* extend min_coin to rpc calls & cli for coin selection  (#12274)

* add tests to test if min_coin is working

they are passing, but no harm in being safe

* expand min coin amount across wallet.py

* extend to trade_manager

* add new options to rpc's

almost done lol.

* add min_coin_amount to wallet send

* make param non optional

alleviate None errors

* add cat wallet changes, rpc and all + fix a bug i accidentally made

oops

* Fix offer compression backwards compatibility

* bumping gui pin to head of release/1.5.0

* Calculate NFT royalty amount

* Create NFT wallet after the DID created (#12175)

* Bumping gui

* Show total amount to be paid for NFT offers

* Fix for NFT0 and NFT+Royalty detection suggested by quex

* Linter fix and formatting change

* Add RPCs for getting/extending the current derivation path index (#12472)

* Sleep to allow neworking layer to execute (#12463)

* Sleep to allow neworking layer to execute

* Add comment

* Added param to indicate how many additional phs create_more_puzzle_hashes should create. (#12493)

Account for range() not including last_index when `up_to_index` is provided.

* Fixed the wallet db rename from v2/v1 to v2_r1.
Removed vestigial code for dealing with the lite wallet db now that
we're syncing v2_r1 from scratch.

* When extending the derivation index, make sure we don't mark previously (#12513)

unused indices as used. This helps minimize gaps in the address space.

* Updating SBX asset ID

* Adding 1.5.0 changelog (#56)

* Adding 1.5.0 changelog

* Adding CVE fix

* Updating gitmodules (#57)

* Updating gitmodules

* Pinning gui

* black fixes

* mypy fixes

* xfail some run_block tests that need CAT2 update

* fix test

* Fix test based on series<->edition changes

* Drop EOL impish and hirsute (#12559)

(cherry picked from commit 189790ced2)

* Expand select_coins rpc  (#12360)

* change type to uint64, 128 is too big anyway

* add new options to select_coins endpoint

* oops

* add tests and finalize

* oops

(cherry picked from commit d5bf4d8b59)

* .resolve() for wallet db path tests in windows

* followup to actually fix the wallet db path tests

* Update .gitmodules

* Update wallet_node.py

* Update trade_manager.py

Co-authored-by: Sebastjan <trepca@gmail.com>
Co-authored-by: matt <matt@chia.net>
Co-authored-by: William Allen <wallentx@users.noreply.github.com>
Co-authored-by: wallentx <william.allentx@gmail.com>
Co-authored-by: Chris Marslender <chrismarslender@gmail.com>
Co-authored-by: Jack Nelson <jack@jacknelson.xyz>
Co-authored-by: Mariano Sorgente <3069354+mariano54@users.noreply.github.com>
Co-authored-by: Matt Hauff <quexington@gmail.com>
Co-authored-by: Jeff Cruikshank <jeff@chia.net>
Co-authored-by: Kronus91 <t.yu@chia.net>
Co-authored-by: Justin England <justin@chia.net>
Co-authored-by: Earle Lowe <e.lowe@chia.net>
Co-authored-by: Earle Lowe <30607889+emlowe@users.noreply.github.com>
This commit is contained in:
Kyle Altendorf 2022-07-29 17:58:21 -04:00 committed by GitHub
parent 4b8130ec60
commit e5bc89e5b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 646 additions and 481 deletions

2
.gitmodules vendored
View File

@ -1,7 +1,7 @@
[submodule "chia-blockchain-gui"] [submodule "chia-blockchain-gui"]
path = chia-blockchain-gui path = chia-blockchain-gui
url = https://github.com/Chia-Network/chia-blockchain-gui.git url = https://github.com/Chia-Network/chia-blockchain-gui.git
branch = pools branch = main
[submodule "mozilla-ca"] [submodule "mozilla-ca"]
path = mozilla-ca path = mozilla-ca
url = https://github.com/Chia-Network/mozilla-ca.git url = https://github.com/Chia-Network/mozilla-ca.git

View File

@ -10,15 +10,49 @@ for setuptools_scm/PEP 440 reasons.
### What's Changed ### What's Changed
## 1.5.0 Chia blockchain 2022-7-26
### Added
- Added derivation index information to the Wallet UI to show the current derivation index height
- Added section in Settings to allow the user to manually update the derivation index height in order to ensure the wallet finds all the coins
- Added a tooltip for users to understand why their CAT balance has changed as new CAT2 tokens get re-issued
- There is now a `blockchain_wallet_v2_r1_*.sqlite` DB that will be created, which will sync from 0 to look for CAT2 tokens. This preserves a copy of your previous wallet DB so that you are able to look up previous transactions by using an older wallet client
- Extended `min_coin` to RPC calls, and CLI for coin selection
- Show DID in the offer preview for NFTs
- Added wallet RPCs (`get_derivation_index`, `update_derivation_index`) to enable the GUI, and CLI to report what the current derivation index is for scanning wallet addresses, and also allows a user to move that index forward to broaden the set of addresses to scan for coins
### Changed
- Changed the DID Wallet to use the new coin selection algorithm that the Standard Wallet, and the CAT Wallet already use
- Changed returning the result of send_transaction to happen after the transaction has been added to the queue, rather than it just being added to the mempool.
- Increased the priority of wallet transactions vs full node broadcasted transactions, so we don't have to wait in line as a wallet user
- Deprecated the `-st, --series-total` and `-sn, --series-number` RPC and CLI NFT minting options in favor of `-ec, --edition-count` and `-en, --edition-number` to align with NFT industry terms
- When creating a DID profile, a DID-linked NFT wallet is automatically created
- Update `chia wallet take_offer` to show NFT royalties that will be paid out when an offer is taken
- Added a parameter to indicate how many additional puzzle hashes `create_more_puzzle_hashes` should create
### Fixed
- Fixed [CVE-2022-36447] where in tokens previously minted on the Chia blockchain using the `CAT1` standard can be inflated in arbitrary amounts by any holder of the token. Total amount of the token can be increased as high as the malicious actor pleases. This is true for every `CAT1` on the Chia blockchain, regardless of issuance rules. This attack is auditable on-chain, so maliciously altered coins can potentially be "marked" by off-chain observers as malicious.
- Fixed issue that prevented websockets from being attempted if an earlier websocket failed
- Fixed issue where `test_smallest_coin_over_amount` did not work properly when all coins were smaller than the amount
- Fixed a performance issue with knapsack that caused it to keep searching for more coins than could actually be selected. Performance with 200k coins:
- Old: 60 seconds
- New: 0.78 seconds
- Fixed offer compression backwards compatibility
- Fixed royalty percentage check for NFT0 NFTs, and made the check for an offer containing an NFT more generalized
- Fixed timing with asyncio context switching that could prevent networking layer from responding to ping
## 1.4.0 Chia blockchain 2022-6-29 ## 1.4.0 Chia blockchain 2022-6-29
### Added ### Added
- Added support for NFTs!!! :party: - Added support for NFTs!!! :party:
- Added `chia wallet nft` command (see https://docs.chia.net/docs/13cli/did_cli) - Added `chia wallet nft` command (see <https://docs.chia.net/docs/13cli/did_cli>)
- Added `chia wallet did` command (see https://docs.chia.net/docs/12rpcs/nft_rpcs) - Added `chia wallet did` command (see <https://docs.chia.net/docs/12rpcs/nft_rpcs>)
- Added RPCs for DID (see https://docs.chia.net/docs/12rpcs/did_rpcs) - Added RPCs for DID (see <https://docs.chia.net/docs/12rpcs/did_rpcs>)
- Added RPCs for NFT (see https://docs.chia.net/docs/12rpcs/nft_rpcs) - Added RPCs for NFT (see <https://docs.chia.net/docs/12rpcs/nft_rpcs>)
- Enable stricter mempool rule when dealing with multiple extra arguments - Enable stricter mempool rule when dealing with multiple extra arguments
- Added a retry when loading pool info from a pool at 2 minute intervals - Added a retry when loading pool info from a pool at 2 minute intervals
- Added CLI options `--sort-by-height` and sort-by-relevance` to `chia wallet get_transactions` - Added CLI options `--sort-by-height` and sort-by-relevance` to `chia wallet get_transactions`
@ -228,7 +262,7 @@ There is a known issue where harvesters will not reconnect to the farmer automat
## 1.3.0 Chia blockchain 2022-3-07 ## 1.3.0 Chia blockchain 2022-3-07
### Added: ### Added
- CAT wallet support - add wallets for your favorite CATs. - CAT wallet support - add wallets for your favorite CATs.
- Offers - make, take, and share your offers. - Offers - make, take, and share your offers.
@ -248,7 +282,7 @@ There is a known issue where harvesters will not reconnect to the farmer automat
- Added *multiprocessing_start_method:* entry in config.yaml that allows setting the python *start method* for multiprocessing (default is *spawn* on Windows & MacOS, *fork* on Unix). - Added *multiprocessing_start_method:* entry in config.yaml that allows setting the python *start method* for multiprocessing (default is *spawn* on Windows & MacOS, *fork* on Unix).
- Added option to "Cancel transaction" accepted offers that are stuck in "pending". - Added option to "Cancel transaction" accepted offers that are stuck in "pending".
### Changed: ### Changed
- Lite wallet client sync updated to only require 3 peers instead of 5. - Lite wallet client sync updated to only require 3 peers instead of 5.
- Only CATs from the default CAT list will be automatically added, all other unknown CATs will need to be manually added (thanks to @ojura, this behavior can be toggled in config.yaml). - Only CATs from the default CAT list will be automatically added, all other unknown CATs will need to be manually added (thanks to @ojura, this behavior can be toggled in config.yaml).
@ -277,7 +311,7 @@ There is a known issue where harvesters will not reconnect to the farmer automat
- It should not be expected that wallet info, such as payout address, should not reflect what their desired values until everything has completed syncing. - It should not be expected that wallet info, such as payout address, should not reflect what their desired values until everything has completed syncing.
- The payout instructions may not be editable via the GUI until syncing has completed. - The payout instructions may not be editable via the GUI until syncing has completed.
### Fixed: ### Fixed
- Offer history limit has been fixed to show all offers now instead of limiting to just 49 offers. - Offer history limit has been fixed to show all offers now instead of limiting to just 49 offers.
- Fixed issues with using madmax CLI options -w, -G, -2, -t and -d (Issue 9163) (thanks @randomisresistance and @lasers8oclockday1). - Fixed issues with using madmax CLI options -w, -G, -2, -t and -d (Issue 9163) (thanks @randomisresistance and @lasers8oclockday1).
@ -302,7 +336,7 @@ There is a known issue where harvesters will not reconnect to the farmer automat
- Memory leak in the full node sync store where peak hashes were stored without being pruned. - Memory leak in the full node sync store where peak hashes were stored without being pruned.
- Fixed a timelord issue which could cause a few blocks to not be infused on chain if a certain proof of space signs conflicting blocks. - Fixed a timelord issue which could cause a few blocks to not be infused on chain if a certain proof of space signs conflicting blocks.
### Known Issues: ### Known Issues
- When you are adding plots and you choose the option to “create a Plot NFT”, you will get an error message “Initial_target_state” and the plots will not get created. - When you are adding plots and you choose the option to “create a Plot NFT”, you will get an error message “Initial_target_state” and the plots will not get created.
- Workaround: Create the Plot NFT first in the “Pool” tab, and then add your plots and choose the created plot NFT in the drop down. - Workaround: Create the Plot NFT first in the “Pool” tab, and then add your plots and choose the created plot NFT in the drop down.
@ -317,11 +351,10 @@ There is a known issue where harvesters will not reconnect to the farmer automat
## 1.2.11 Chia blockchain 2021-11-4 ## 1.2.11 Chia blockchain 2021-11-4
Farmers rejoice: today's release integrates two plotters in broad use in the Chia community: Bladebit, created by @harold-b, and Madmax, created by @madMAx43v3r. Both of these plotters bring significant improvements in plotting time. More plotting info [here](https://github.com/Chia-Network/chia-blockchain/wiki/Alternative--Plotters).
This release also includes several important performance improvements as a result of last weekends "Dust Storm", with two goals in mind: make sure everyone can farm at all times, and improve how many transactions per second each node can accept, especially for low-end hardware. Please know that these optimizations are only the first wave in a series of many over the next few releases to help address this going forward. While the changes we have implemented in this update may not necessarily solve for _every_ possible congestion scenario, they should go a long way towards helping low-end systems perform closer to expectations if this happens again.
### Added ### Added
- Farmers rejoice: today's release integrates two plotters in broad use in the Chia community: Bladebit, created by @harold-b, and Madmax, created by @madMAx43v3r. Both of these plotters bring significant improvements in plotting time. More plotting info [here](https://github.com/Chia-Network/chia-blockchain/wiki/Alternative--Plotters).
- This release also includes several important performance improvements as a result of last weekends "Dust Storm", with two goals in mind: make sure everyone can farm at all times, and improve how many transactions per second each node can accept, especially for low-end hardware. Please know that these optimizations are only the first wave in a series of many over the next few releases to help address this going forward. While the changes we have implemented in this update may not necessarily solve for *every* possible congestion scenario, they should go a long way towards helping low-end systems perform closer to expectations if this happens again.
- Performance improvements for nodes to support higher transaction volumes, especially for low powered devices like RaspBerry Pi. Full details at [#9050](https://github.com/Chia-Network/chia-blockchain/pull/9050). - Performance improvements for nodes to support higher transaction volumes, especially for low powered devices like RaspBerry Pi. Full details at [#9050](https://github.com/Chia-Network/chia-blockchain/pull/9050).
- Improved multi-core usage through process pools. - Improved multi-core usage through process pools.
- Prioritized block validation. - Prioritized block validation.
@ -349,7 +382,6 @@ This release also includes several important performance improvements as a resul
- PlotNFT transactions via CLI (e.g. `chia plotnft join`) now accept a fee parameter, but it is not yet operable. - PlotNFT transactions via CLI (e.g. `chia plotnft join`) now accept a fee parameter, but it is not yet operable.
## 1.2.10 Chia blockchain 2021-10-25 ## 1.2.10 Chia blockchain 2021-10-25
We have some great improvements in this release: We launched our migration of keys to a common encrypted keyring.yaml file, and we secure this with an optional passphrase in both GUI and CLI. We've added a passphrase hint in case you forget your passphrase. More info on our [wiki](https://github.com/Chia-Network/chia-blockchain/wiki/Passphrase-Protected-Chia-Keys-and-Key-Storage-Migration). We also launched a new Chialisp compiler in clvm_tools_rs which substantially improves compile time for Chialisp developers. We also addressed a widely reported issue in which a system failure, such as a power outage, would require some farmers to sync their full node from zero. This release also includes several other improvements and fixes. We have some great improvements in this release: We launched our migration of keys to a common encrypted keyring.yaml file, and we secure this with an optional passphrase in both GUI and CLI. We've added a passphrase hint in case you forget your passphrase. More info on our [wiki](https://github.com/Chia-Network/chia-blockchain/wiki/Passphrase-Protected-Chia-Keys-and-Key-Storage-Migration). We also launched a new Chialisp compiler in clvm_tools_rs which substantially improves compile time for Chialisp developers. We also addressed a widely reported issue in which a system failure, such as a power outage, would require some farmers to sync their full node from zero. This release also includes several other improvements and fixes.
@ -1991,7 +2023,7 @@ relic. We will make a patch available for these systems shortly.
### Added ### Added
- There is now full transaction support on the Chia blockchain. In this initial Beta 1.0 release, all transaction types are supported though the wallets and UIs currently only directly support basic transactions like coinbase rewards and sending coins while paying fees. UI support for our [smart transactions](https://github.com/Chia-Network/wallets/blob/main/README.md) will be available in the UIs shortly. - There is now full transaction support on the Chia blockchain. In this initial Beta 1.0 release, all transaction types are supported though the wallets and UIs currently only directly support basic transactions like coinbase rewards and sending coins while paying fees. UI support for our [smart transactions](https://github.com/Chia-Network/wallets/blob/main/README.md) will be available in the UIs shortly.
- Wallet and Node GUIs are available on Windows, Mac, and desktop Linux platforms. We now use an Electron UI that is a full light client wallet that can also serve as a node UI. Our Windows Electron Wallet can run standalone by connecting to other nodes on the network or another node you run. WSL 2 on Windows can run everything except the Wallet but you can run the Wallet on the native Windows side of the same machine. Also the WSL 2 install process is 3 times faster and _much_ easier. Windows native node/farmer/plotting functionality are coming soon. - Wallet and Node GUIs are available on Windows, Mac, and desktop Linux platforms. We now use an Electron UI that is a full light client wallet that can also serve as a node UI. Our Windows Electron Wallet can run standalone by connecting to other nodes on the network or another node you run. WSL 2 on Windows can run everything except the Wallet but you can run the Wallet on the native Windows side of the same machine. Also the WSL 2 install process is 3 times faster and *much* easier. Windows native node/farmer/plotting functionality are coming soon.
- Install is significantly easier with less dependencies on all supported platforms. - Install is significantly easier with less dependencies on all supported platforms.
- If youre a farmer you can use the Wallet to keep track of your earnings. Either use the same keys.yaml on the same machine or copy the keys.yaml to another machine where you want to track of and spend your coins. - If youre a farmer you can use the Wallet to keep track of your earnings. Either use the same keys.yaml on the same machine or copy the keys.yaml to another machine where you want to track of and spend your coins.
- We have continued to make improvements to the speed of VDF squaring, creating a VDF proof, and verifying a VDF proof. - We have continued to make improvements to the speed of VDF squaring, creating a VDF proof, and verifying a VDF proof.

@ -1 +1 @@
Subproject commit f62c216cce6b89ef23a1b2b0a2dd6fc2a439649a Subproject commit baa47b29db10b0408c051cbf7da8f6e1f31a7b66

View File

@ -4,8 +4,8 @@ from typing import Any, Dict, Optional, Tuple
import click import click
from chia.cmds.plotnft import validate_fee from chia.cmds.plotnft import validate_fee
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.transaction_sorting import SortKey from chia.wallet.transaction_sorting import SortKey
from chia.wallet.util.wallet_types import WalletType
@click.group("wallet", short_help="Manage your wallet") @click.group("wallet", short_help="Manage your wallet")
@ -574,8 +574,12 @@ def nft_wallet_create_cmd(
@click.option("-mu", "--metadata-uris", help="Comma separated list of metadata URIs", type=str) @click.option("-mu", "--metadata-uris", help="Comma separated list of metadata URIs", type=str)
@click.option("-lh", "--license-hash", help="NFT license hash", type=str, default="") @click.option("-lh", "--license-hash", help="NFT license hash", type=str, default="")
@click.option("-lu", "--license-uris", help="Comma separated list of license URIs", type=str) @click.option("-lu", "--license-uris", help="Comma separated list of license URIs", type=str)
@click.option("-st", "--series-total", help="NFT series total number", type=int, default=1, show_default=True) @click.option(
@click.option("-sn", "--series-number", help="NFT seriese number", type=int, default=1, show_default=True) "-st", "--series-total", help="[DEPRECATED] NFT series total number", type=int, default=1, show_default=True
)
@click.option("-sn", "--series-number", help="[DEPRECATED] NFT series number", type=int, default=1, show_default=True)
@click.option("-ec", "--edition-count", help="NFT edition count, defaults to 1", type=int)
@click.option("-en", "--edition-number", help="NFT edition number, defaults to 1", type=int)
@click.option( @click.option(
"-m", "-m",
"--fee", "--fee",
@ -608,6 +612,8 @@ def nft_mint_cmd(
license_uris: Optional[str], license_uris: Optional[str],
series_total: Optional[int], series_total: Optional[int],
series_number: Optional[int], series_number: Optional[int],
edition_count: Optional[int],
edition_number: Optional[int],
fee: str, fee: str,
royalty_percentage_fraction: int, royalty_percentage_fraction: int,
) -> None: ) -> None:
@ -624,6 +630,14 @@ def nft_mint_cmd(
else: else:
license_uris_list = [lu.strip() for lu in license_uris.split(",")] license_uris_list = [lu.strip() for lu in license_uris.split(",")]
if not (edition_number and edition_count):
if series_number and series_total:
print("\nWARNING: Series total(-st) and number(-sn) options are *deprecated*, please use -en and -ec.\n")
edition_number = series_number
edition_count = series_total
else:
edition_number = 1
edition_count = 1
extra_params = { extra_params = {
"wallet_id": id, "wallet_id": id,
"royalty_address": royalty_address, "royalty_address": royalty_address,
@ -635,8 +649,8 @@ def nft_mint_cmd(
"metadata_uris": metadata_uris_list, "metadata_uris": metadata_uris_list,
"license_hash": license_hash, "license_hash": license_hash,
"license_uris": license_uris_list, "license_uris": license_uris_list,
"series_total": series_total, "edition_count": edition_count,
"series_number": series_number, "edition_number": edition_number,
"fee": fee, "fee": fee,
"royalty_percentage": royalty_percentage_fraction, "royalty_percentage": royalty_percentage_fraction,
} }

View File

@ -29,7 +29,6 @@ from chia.wallet.util.wallet_types import WalletType
CATNameResolver = Callable[[bytes32], Awaitable[Optional[Tuple[Optional[uint32], str]]]] CATNameResolver = Callable[[bytes32], Awaitable[Optional[Tuple[Optional[uint32], str]]]]
transaction_type_descriptions = { transaction_type_descriptions = {
TransactionType.INCOMING_TX: "received", TransactionType.INCOMING_TX: "received",
TransactionType.OUTGOING_TX: "sent", TransactionType.OUTGOING_TX: "sent",
@ -532,16 +531,50 @@ async def take_offer(args: dict, wallet_client: WalletRpcClient, fingerprint: in
print("Please enter a valid offer file or hex blob") print("Please enter a valid offer file or hex blob")
return return
offered, requested, _ = offer.summary() offered, requested, driver_dict = offer.summary()
cat_name_resolver = wallet_client.cat_asset_id_to_name cat_name_resolver = wallet_client.cat_asset_id_to_name
print("Summary:") print("Summary:")
print(" OFFERED:") print(" OFFERED:")
await print_offer_summary(cat_name_resolver, offered) await print_offer_summary(cat_name_resolver, offered)
print(" REQUESTED:") print(" REQUESTED:")
await print_offer_summary(cat_name_resolver, requested) await print_offer_summary(cat_name_resolver, requested)
print()
nft_coin_id: Optional[bytes32] = nft_coin_id_supporting_royalties_from_offer(driver_dict)
nft_royalty_percentage: int = (
0 if nft_coin_id is None else await get_nft_royalty_percentage(nft_coin_id, wallet_client)
)
nft_total_amount_requested_str: Optional[str] = None
if nft_coin_id is not None and nft_royalty_percentage > 0:
print("NFT Royalty Fee:")
nft_royalty_asset_id, nft_royalty_amount, nft_total_amount_requested = calculate_nft_royalty_amount(
offered, requested, nft_coin_id, nft_royalty_percentage
)
nft_royalty_currency: str = "Unknown CAT"
if nft_royalty_asset_id == "xch":
nft_royalty_currency = "XCH"
else:
result = await cat_name_resolver(bytes32.fromhex(nft_royalty_asset_id))
if result is not None:
nft_royalty_currency = result[1]
nft_royalty_divisor = units["chia"] if nft_royalty_asset_id == "xch" else units["cat"]
nft_total_amount_requested_str = (
f"{Decimal(nft_total_amount_requested) / nft_royalty_divisor} {nft_royalty_currency}"
)
print(
f" {Decimal(nft_royalty_amount) / nft_royalty_divisor} {nft_royalty_currency} "
f"({nft_royalty_amount} mojos)"
)
print(f"Included Fees: {Decimal(offer.bundle.fees()) / units['chia']}") print(f"Included Fees: {Decimal(offer.bundle.fees()) / units['chia']}")
if nft_total_amount_requested_str is not None:
print(f"Total Amount Requested: {nft_total_amount_requested_str}")
if not examine_only: if not examine_only:
print()
confirmation = input("Would you like to take this offer? (y/n): ") confirmation = input("Would you like to take this offer? (y/n): ")
if confirmation in ["y", "yes"]: if confirmation in ["y", "yes"]:
trade_record = await wallet_client.take_offer(offer, fee=fee) trade_record = await wallet_client.take_offer(offer, fee=fee)
@ -574,7 +607,7 @@ def wallet_coin_unit(typ: WalletType, address_prefix: str) -> Tuple[str, int]:
def print_balance(amount: int, scale: int, address_prefix: str) -> str: def print_balance(amount: int, scale: int, address_prefix: str) -> str:
ret = f"{amount/scale} {address_prefix} " ret = f"{amount / scale} {address_prefix} "
if scale > 1: if scale > 1:
ret += f"({amount} mojo)" ret += f"({amount} mojo)"
return ret return ret
@ -669,7 +702,7 @@ async def get_wallet(wallet_client: WalletRpcClient, fingerprint: int = None) ->
current_sync_status = "Not Synced" current_sync_status = "Not Synced"
print("Wallet keys:") print("Wallet keys:")
for i, fp in enumerate(fingerprints): for i, fp in enumerate(fingerprints):
row: str = f"{i+1}) " row: str = f"{i + 1}) "
row += "* " if fp == logged_in_fingerprint else spacing row += "* " if fp == logged_in_fingerprint else spacing
row += f"{fp}" row += f"{fp}"
if fp == logged_in_fingerprint and len(current_sync_status) > 0: if fp == logged_in_fingerprint and len(current_sync_status) > 0:
@ -802,8 +835,8 @@ async def mint_nft(args: Dict, wallet_client: WalletRpcClient, fingerprint: int)
metadata_uris = args["metadata_uris"] metadata_uris = args["metadata_uris"]
license_hash = args["license_hash"] license_hash = args["license_hash"]
license_uris = args["license_uris"] license_uris = args["license_uris"]
series_total = args["series_total"] edition_count = args["edition_count"]
series_number = args["series_number"] edition_number = args["edition_number"]
fee: int = int(Decimal(args["fee"]) * units["chia"]) fee: int = int(Decimal(args["fee"]) * units["chia"])
royalty_percentage = args["royalty_percentage"] royalty_percentage = args["royalty_percentage"]
try: try:
@ -831,8 +864,8 @@ async def mint_nft(args: Dict, wallet_client: WalletRpcClient, fingerprint: int)
metadata_uris, metadata_uris,
license_hash, license_hash,
license_uris, license_uris,
series_total, edition_count,
series_number, edition_number,
fee, fee,
royalty_percentage, royalty_percentage,
did_id, did_id,
@ -958,3 +991,40 @@ async def get_nft_info(args: Dict, wallet_client: WalletRpcClient, fingerprint:
print_nft_info(nft_info, config=config) print_nft_info(nft_info, config=config)
except Exception as e: except Exception as e:
print(f"Failed to get NFT info: {e}") print(f"Failed to get NFT info: {e}")
async def get_nft_royalty_percentage(nft_coin_id: bytes32, wallet_client: WalletRpcClient) -> int:
info = NFTInfo.from_json_dict((await wallet_client.get_nft_info(nft_coin_id.hex()))["nft_info"])
return info.royalty_percentage if info.royalty_percentage is not None else 0
def calculate_nft_royalty_amount(
offered: Dict[str, Any], requested: Dict[str, Any], nft_coin_id: bytes32, nft_royalty_percentage: int
) -> Tuple[str, int, int]:
nft_asset_id = nft_coin_id.hex()
amount_dict: Dict[str, Any] = requested if nft_asset_id in offered else offered
amounts: List[Tuple[str, int]] = list(amount_dict.items())
if len(amounts) != 1 or not isinstance(amounts[0][1], int):
raise ValueError("Royalty enabled NFTs only support offering/requesting one NFT for one currency")
royalty_amount: uint64 = uint64(amounts[0][1] * nft_royalty_percentage / 10000)
royalty_asset_id = amounts[0][0]
total_amount_requested = (requested[royalty_asset_id] if amount_dict == requested else 0) + royalty_amount
return royalty_asset_id, royalty_amount, total_amount_requested
def driver_dict_asset_is_nft_supporting_royalties(driver_dict: Dict[str, Any], asset_id: str) -> bool:
asset_dict: Dict[str, Any] = driver_dict[asset_id]
return (
asset_dict.get("type") == "singleton"
and asset_dict.get("also", {}).get("type") == "metadata"
and asset_dict.get("also", {}).get("also", {}).get("type") == "ownership"
)
def nft_coin_id_supporting_royalties_from_offer(driver_dict: Dict[str, Any]) -> Optional[bytes32]:
nft_asset_id: Optional[str] = next(
(key for key in driver_dict.keys() if driver_dict_asset_is_nft_supporting_royalties(driver_dict, key)), None
)
return bytes32.fromhex(nft_asset_id) if nft_asset_id is not None else None

View File

@ -1386,8 +1386,8 @@ class WalletRpcApi:
("h", hexstr_to_bytes(request["hash"])), ("h", hexstr_to_bytes(request["hash"])),
("mu", request.get("meta_uris", [])), ("mu", request.get("meta_uris", [])),
("lu", request.get("license_uris", [])), ("lu", request.get("license_uris", [])),
("sn", uint64(request.get("series_number", 1))), ("sn", uint64(request.get("edition_number", 1))),
("st", uint64(request.get("series_total", 1))), ("st", uint64(request.get("edition_total", 1))),
] ]
if "meta_hash" in request and len(request["meta_hash"]) > 0: if "meta_hash" in request and len(request["meta_hash"]) > 0:
metadata_list.append(("mh", hexstr_to_bytes(request["meta_hash"]))) metadata_list.append(("mh", hexstr_to_bytes(request["meta_hash"])))

View File

@ -641,8 +641,8 @@ class WalletRpcClient(RpcClient):
meta_uris=[], meta_uris=[],
license_hash="", license_hash="",
license_uris=[], license_uris=[],
series_total=1, edition_count=1,
series_number=1, edition_number=1,
fee=0, fee=0,
royalty_percentage=0, royalty_percentage=0,
did_id=None, did_id=None,
@ -657,8 +657,8 @@ class WalletRpcClient(RpcClient):
"meta_uris": meta_uris, "meta_uris": meta_uris,
"license_hash": license_hash, "license_hash": license_hash,
"license_uris": license_uris, "license_uris": license_uris,
"series_number": series_number, "series_number": edition_number,
"series_total": series_total, "series_total": edition_count,
"royalty_percentage": royalty_percentage, "royalty_percentage": royalty_percentage,
"did_id": did_id, "did_id": did_id,
"fee": fee, "fee": fee,

View File

@ -2,8 +2,5 @@ import os
from pathlib import Path from pathlib import Path
DEFAULT_ROOT_PATH = Path(os.path.expanduser(os.getenv("CHIA_ROOT", "~/.chia/mainnet"))).resolve() DEFAULT_ROOT_PATH = Path(os.path.expanduser(os.getenv("CHIA_ROOT", "~/.chia/mainnet"))).resolve()
STANDALONE_ROOT_PATH = Path(
os.path.expanduser(os.getenv("CHIA_STANDALONE_WALLET_ROOT", "~/.chia/standalone_wallet"))
).resolve()
DEFAULT_KEYS_ROOT_PATH = Path(os.path.expanduser(os.getenv("CHIA_KEYS_ROOT", "~/.chia_keys"))).resolve() DEFAULT_KEYS_ROOT_PATH = Path(os.path.expanduser(os.getenv("CHIA_KEYS_ROOT", "~/.chia_keys"))).resolve()

View File

@ -1,5 +1,5 @@
SPACEBUCKS = { SPACEBUCKS = {
"asset_id": "78ad32a8c9ea70f27d73e9306fc467bab2a6b15b30289791e37ab6e8612212b1", "asset_id": "a628c1c2c6fcb74d53746157e438e108eab5c0bb3e5c80ff9b1910b3e4832913",
"name": "Spacebucks", "name": "Spacebucks",
"symbol": "SBX", "symbol": "SBX",
} }

View File

@ -622,7 +622,7 @@ class CATWallet:
for coin in cat_coins: for coin in cat_coins:
if first: if first:
first = False first = False
announcement = Announcement(coin.name(), std_hash(b"".join([c.name() for c in cat_coins])), b"\xca") announcement = Announcement(coin.name(), std_hash(b"".join([c.name() for c in cat_coins])))
if need_chia_transaction: if need_chia_transaction:
if fee > regular_chia_to_claim: if fee > regular_chia_to_claim:
chia_tx, _ = await self.create_tandem_xch_tx( chia_tx, _ = await self.create_tandem_xch_tx(

View File

@ -1 +0,0 @@
ff02ffff01ff02ff5effff04ff02ffff04ffff04ff05ffff04ffff0bff2cff0580ffff04ff0bff80808080ffff04ffff02ff17ff2f80ffff04ff5fffff04ffff02ff2effff04ff02ffff04ff17ff80808080ffff04ffff0bff82027fff82057fff820b7f80ffff04ff81bfffff04ff82017fffff04ff8202ffffff04ff8205ffffff04ff820bffff80808080808080808080808080ffff04ffff01ffffffff81ca3dff46ff0233ffff3c04ff01ff0181cbffffff02ff02ffff03ff05ffff01ff02ff32ffff04ff02ffff04ff0dffff04ffff0bff22ffff0bff2cff3480ffff0bff22ffff0bff22ffff0bff2cff5c80ff0980ffff0bff22ff0bffff0bff2cff8080808080ff8080808080ffff010b80ff0180ffff02ffff03ff0bffff01ff02ffff03ffff09ffff02ff2effff04ff02ffff04ff13ff80808080ff820b9f80ffff01ff02ff26ffff04ff02ffff04ffff02ff13ffff04ff5fffff04ff17ffff04ff2fffff04ff81bfffff04ff82017fffff04ff1bff8080808080808080ffff04ff82017fff8080808080ffff01ff088080ff0180ffff01ff02ffff03ff17ffff01ff02ffff03ffff20ff81bf80ffff0182017fffff01ff088080ff0180ffff01ff088080ff018080ff0180ffff04ffff04ff05ff2780ffff04ffff10ff0bff5780ff778080ff02ffff03ff05ffff01ff02ffff03ffff09ffff02ffff03ffff09ff11ff7880ffff0159ff8080ff0180ffff01818f80ffff01ff02ff7affff04ff02ffff04ff0dffff04ff0bffff04ffff04ff81b9ff82017980ff808080808080ffff01ff02ff5affff04ff02ffff04ffff02ffff03ffff09ff11ff7880ffff01ff04ff78ffff04ffff02ff36ffff04ff02ffff04ff13ffff04ff29ffff04ffff0bff2cff5b80ffff04ff2bff80808080808080ff398080ffff01ff02ffff03ffff09ff11ff2480ffff01ff04ff24ffff04ffff0bff20ff2980ff398080ffff010980ff018080ff0180ffff04ffff02ffff03ffff09ff11ff7880ffff0159ff8080ff0180ffff04ffff02ff7affff04ff02ffff04ff0dffff04ff0bffff04ff17ff808080808080ff80808080808080ff0180ffff01ff04ff80ffff04ff80ff17808080ff0180ffffff02ffff03ff05ffff01ff04ff09ffff02ff26ffff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ff0bff22ffff0bff2cff5880ffff0bff22ffff0bff22ffff0bff2cff5c80ff0580ffff0bff22ffff02ff32ffff04ff02ffff04ff07ffff04ffff0bff2cff2c80ff8080808080ffff0bff2cff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bff2cff058080ff0180ffff04ffff04ff28ffff04ff5fff808080ffff02ff7effff04ff02ffff04ffff04ffff04ff2fff0580ffff04ff5fff82017f8080ffff04ffff02ff7affff04ff02ffff04ff0bffff04ff05ffff01ff808080808080ffff04ff17ffff04ff81bfffff04ff82017fffff04ffff0bff8204ffffff02ff36ffff04ff02ffff04ff09ffff04ff820affffff04ffff0bff2cff2d80ffff04ff15ff80808080808080ff8216ff80ffff04ff8205ffffff04ff820bffff808080808080808080808080ff02ff2affff04ff02ffff04ff5fffff04ff3bffff04ffff02ffff03ff17ffff01ff09ff2dffff0bff27ffff02ff36ffff04ff02ffff04ff29ffff04ff57ffff04ffff0bff2cff81b980ffff04ff59ff80808080808080ff81b78080ff8080ff0180ffff04ff17ffff04ff05ffff04ff8202ffffff04ffff04ffff04ff24ffff04ffff0bff7cff2fff82017f80ff808080ffff04ffff04ff30ffff04ffff0bff81bfffff0bff7cff15ffff10ff82017fffff11ff8202dfff2b80ff8202ff808080ff808080ff138080ff80808080808080808080ff018080

View File

@ -1 +0,0 @@
72dec062874cd4d3aab892a0906688a1ae412b0109982e1797a170add88bdcdc

View File

@ -1,6 +1,6 @@
from chia.wallet.puzzles.load_clvm import load_clvm from chia.wallet.puzzles.load_clvm import load_clvm
CAT_MOD = load_clvm("cat.clvm", package_or_requirement=__name__) CAT_MOD = load_clvm("cat_v2.clvm", package_or_requirement=__name__)
LOCK_INNER_PUZZLE = load_clvm("lock.inner.puzzle.clvm", package_or_requirement=__name__) LOCK_INNER_PUZZLE = load_clvm("lock.inner.puzzle.clvm", package_or_requirement=__name__)
CAT_MOD_HASH = CAT_MOD.get_tree_hash() CAT_MOD_HASH = CAT_MOD.get_tree_hash()

View File

@ -1,417 +1,397 @@
; Coins locked with this puzzle are spendable cats. ; Coins locked with this puzzle are spendable cats.
; ;
; Choose a list of n inputs (n>=1), I_1, ... I_n with amounts A_1, ... A_n. ; Choose a list of n inputs (n>=1), I_1, ... I_n with amounts A_1, ... A_n.
; ;
; We put them in a ring, so "previous" and "next" have intuitive k-1 and k+1 semantics, ; We put them in a ring, so "previous" and "next" have intuitive k-1 and k+1 semantics,
; wrapping so {n} and 0 are the same, ie. all indices are mod n. ; wrapping so {n} and 0 are the same, ie. all indices are mod n.
; ;
; Each coin creates 0 or more coins with total output value O_k. ; Each coin creates 0 or more coins with total output value O_k.
; Let D_k = the "debt" O_k - A_k contribution of coin I_k, ie. how much debt this input accumulates. ; Let D_k = the "debt" O_k - A_k contribution of coin I_k, ie. how much debt this input accumulates.
; Some coins may spend more than they contribute and some may spend less, ie. D_k need ; Some coins may spend more than they contribute and some may spend less, ie. D_k need
; not be zero. That's okay. It's enough for the total of all D_k in the ring to be 0. ; not be zero. That's okay. It's enough for the total of all D_k in the ring to be 0.
; ;
; A coin can calculate its own D_k since it can verify A_k (it's hashed into the coin id) ; A coin can calculate its own D_k since it can verify A_k (it's hashed into the coin id)
; and it can sum up `CREATE_COIN` conditions for O_k. ; and it can sum up `CREATE_COIN` conditions for O_k.
; ;
; Defines a "subtotal of debts" S_k for each coin as follows: ; Defines a "subtotal of debts" S_k for each coin as follows:
; ;
; S_1 = 0 ; S_1 = 0
; S_k = S_{k-1} + D_{k-1} ; S_k = S_{k-1} + D_{k-1}
; ;
; Here's the main trick that shows the ring sums to 0. ; Here's the main trick that shows the ring sums to 0.
; You can prove by induction that S_{k+1} = D_1 + D_2 + ... + D_k. ; You can prove by induction that S_{k+1} = D_1 + D_2 + ... + D_k.
; But it's a ring, so S_{n+1} is also S_1, which is 0. So D_1 + D_2 + ... + D_k = 0. ; But it's a ring, so S_{n+1} is also S_1, which is 0. So D_1 + D_2 + ... + D_k = 0.
; So the total debts must be 0, ie. no coins are created or destroyed. ; So the total debts must be 0, ie. no coins are created or destroyed.
; ;
; Each coin's solution includes I_{k-1}, I_k, and I_{k+1} along with proofs that I_{k}, and I_{k+1} are CATs of the same type. ; Each coin's solution includes I_{k-1}, I_k, and I_{k+1} along with proofs that I_{k}, and I_{k+1} are CATs of the same type.
; Each coin's solution includes S_{k-1}. It calculates D_k = O_k - A_k, and then S_k = S_{k-1} + D_{k-1} ; Each coin's solution includes S_{k-1}. It calculates D_k = O_k - A_k, and then S_k = S_{k-1} + D_{k-1}
; ;
; Announcements are used to ensure that each S_k follows the pattern is valid. ; Announcements are used to ensure that each S_k follows the pattern is valid.
; Announcements automatically commit to their own coin id. ; Announcements automatically commit to their own coin id.
; Coin I_k creates an announcement that further commits to I_{k-1} and S_{k-1}. ; Coin I_k creates an announcement that further commits to I_{k-1} and S_{k-1}.
; ;
; Coin I_k gets a proof that I_{k+1} is a cat, so it knows it must also create an announcement ; Coin I_k gets a proof that I_{k+1} is a cat, so it knows it must also create an announcement
; when spent. It checks that I_{k+1} creates an announcement committing to I_k and S_k. ; when spent. It checks that I_{k+1} creates an announcement committing to I_k and S_k.
; ;
; So S_{k+1} is correct iff S_k is correct. ; So S_{k+1} is correct iff S_k is correct.
; ;
; Coins also receive proofs that their neighbours are CATs, ensuring the announcements aren't forgeries. ; Coins also receive proofs that their neighbours are CATs, ensuring the announcements aren't forgeries.
; Inner puzzles and the CAT layer prepend `CREATE_COIN_ANNOUNCEMENT` with different prefixes to avoid forgeries. ; Inner puzzles and the CAT layer prepend `CREATE_COIN_ANNOUNCEMENT` with different prefixes to avoid forgeries.
; Ring announcements use 0xcb, and inner puzzles are given 0xca ; Ring announcements use 0xcb, and inner puzzles are given 0xca
; ;
; In summary, I_k generates a coin_announcement Y_k ("Y" for "yell") as follows: ; In summary, I_k generates a coin_announcement Y_k ("Y" for "yell") as follows:
; ;
; Y_k: hash of I_k (automatically), I_{k-1}, S_k ; Y_k: hash of I_k (automatically), I_{k-1}, S_k
; ;
; Each coin creates an assert_coin_announcement to ensure that the next coin's announcement is as expected: ; Each coin creates an assert_coin_announcement to ensure that the next coin's announcement is as expected:
; Y_{k+1} : hash of I_{k+1}, I_k, S_{k+1} ; Y_{k+1} : hash of I_{k+1}, I_k, S_{k+1}
; ;
; TLDR: ; TLDR:
; I_k : coins ; I_k : coins
; A_k : amount coin k contributes ; A_k : amount coin k contributes
; O_k : amount coin k spend ; O_k : amount coin k spend
; D_k : difference/delta that coin k incurs (A - O) ; D_k : difference/delta that coin k incurs (A - O)
; S_k : subtotal of debts D_1 + D_2 ... + D_k ; S_k : subtotal of debts D_1 + D_2 ... + D_k
; Y_k : announcements created by coin k commiting to I_{k-1}, I_k, S_k ; Y_k : announcements created by coin k commiting to I_{k-1}, I_k, S_k
; ;
; All conditions go through a "transformer" that looks for CREATE_COIN conditions ; All conditions go through a "transformer" that looks for CREATE_COIN conditions
; generated by the inner solution, and wraps the puzzle hash ensuring the output is a cat. ; generated by the inner solution, and wraps the puzzle hash ensuring the output is a cat.
; ;
; Three output conditions are prepended to the list of conditions for each I_k: ; Three output conditions are prepended to the list of conditions for each I_k:
; (ASSERT_MY_ID I_k) to ensure that the passed in value for I_k is correct ; (ASSERT_MY_ID I_k) to ensure that the passed in value for I_k is correct
; (CREATE_COIN_ANNOUNCEMENT I_{k-1} S_k) to create this coin's announcement ; (CREATE_COIN_ANNOUNCEMENT I_{k-1} S_k) to create this coin's announcement
; (ASSERT_COIN_ANNOUNCEMENT hashed_announcement(Y_{k+1})) to ensure the next coin really is next and ; (ASSERT_COIN_ANNOUNCEMENT hashed_announcement(Y_{k+1})) to ensure the next coin really is next and
; the relative values of S_k and S_{k+1} are correct ; the relative values of S_k and S_{k+1} are correct
; ;
; This is all we need to do to ensure cats exactly balance in the inputs and outputs. ; This is all we need to do to ensure cats exactly balance in the inputs and outputs.
; ;
; Proof: ; Proof:
; Consider n, k, I_k values, O_k values, S_k and A_k as above. ; Consider n, k, I_k values, O_k values, S_k and A_k as above.
; For the (CREATE_COIN_ANNOUNCEMENT Y_{k+1}) (created by the next coin) ; For the (CREATE_COIN_ANNOUNCEMENT Y_{k+1}) (created by the next coin)
; and (ASSERT_COIN_ANNOUNCEMENT hashed(Y_{k+1})) to match, ; and (ASSERT_COIN_ANNOUNCEMENT hashed(Y_{k+1})) to match,
; we see that I_k can ensure that is has the correct value for S_{k+1}. ; we see that I_k can ensure that is has the correct value for S_{k+1}.
; ;
; By induction, we see that S_{m+1} = sum(i, 1, m) [O_i - A_i] = sum(i, 1, m) O_i - sum(i, 1, m) A_i ; By induction, we see that S_{m+1} = sum(i, 1, m) [O_i - A_i] = sum(i, 1, m) O_i - sum(i, 1, m) A_i
; So S_{n+1} = sum(i, 1, n) O_i - sum(i, 1, n) A_i. But S_{n+1} is actually S_1 = 0, ; So S_{n+1} = sum(i, 1, n) O_i - sum(i, 1, n) A_i. But S_{n+1} is actually S_1 = 0,
; so thus sum(i, 1, n) O_i = sum (i, 1, n) A_i, ie. output total equals input total. ; so thus sum(i, 1, n) O_i = sum (i, 1, n) A_i, ie. output total equals input total.
;; GLOSSARY: ;; GLOSSARY:
;; MOD_HASH: this code's sha256 tree hash ;; MOD_HASH: this code's sha256 tree hash
;; TAIL_PROGRAM_HASH: the program that determines if a coin can mint new cats, burn cats, and check if its lineage is valid if its parent is not a CAT ;; TAIL_PROGRAM_HASH: the program that determines if a coin can mint new cats, burn cats, and check if its lineage is valid if its parent is not a CAT
;; INNER_PUZZLE: an independent puzzle protecting the coins. Solutions to this puzzle are expected to generate `AGG_SIG` conditions and possibly `CREATE_COIN` conditions. ;; INNER_PUZZLE: an independent puzzle protecting the coins. Solutions to this puzzle are expected to generate `AGG_SIG` conditions and possibly `CREATE_COIN` conditions.
;; ---- items above are curried into the puzzle hash ---- ;; ---- items above are curried into the puzzle hash ----
;; inner_puzzle_solution: the solution to the inner puzzle ;; inner_puzzle_solution: the solution to the inner puzzle
;; prev_coin_id: the id for the previous coin ;; prev_coin_id: the id for the previous coin
;; tail_program_reveal: reveal of TAIL_PROGRAM_HASH required to run the program if desired ;; tail_program_reveal: reveal of TAIL_PROGRAM_HASH required to run the program if desired
;; tail_solution: optional solution passed into tail_program ;; tail_solution: optional solution passed into tail_program
;; lineage_proof: optional proof that our coin's parent is a CAT ;; lineage_proof: optional proof that our coin's parent is a CAT
;; this_coin_info: (parent_id puzzle_hash amount) ;; this_coin_info: (parent_id puzzle_hash amount)
;; next_coin_proof: (parent_id inner_puzzle_hash amount) ;; next_coin_proof: (parent_id inner_puzzle_hash amount)
;; prev_subtotal: the subtotal between prev-coin and this-coin ;; prev_subtotal: the subtotal between prev-coin and this-coin
;; extra_delta: an amount that is added to our delta and checked by the TAIL program ;; extra_delta: an amount that is added to our delta and checked by the TAIL program
;; ;;
(mod ( (mod (
MOD_HASH ;; curried into puzzle MOD_HASH ;; curried into puzzle
TAIL_PROGRAM_HASH ;; curried into puzzle TAIL_PROGRAM_HASH ;; curried into puzzle
INNER_PUZZLE ;; curried into puzzle INNER_PUZZLE ;; curried into puzzle
inner_puzzle_solution ;; if invalid, INNER_PUZZLE will fail inner_puzzle_solution ;; if invalid, INNER_PUZZLE will fail
lineage_proof ;; This is the parent's coin info, used to check if the parent was a CAT. Optional if using tail_program. lineage_proof ;; This is the parent's coin info, used to check if the parent was a CAT. Optional if using tail_program.
prev_coin_id ;; used in this coin's announcement, prev_coin ASSERT_COIN_ANNOUNCEMENT will fail if wrong prev_coin_id ;; used in this coin's announcement, prev_coin ASSERT_COIN_ANNOUNCEMENT will fail if wrong
this_coin_info ;; verified with ASSERT_MY_COIN_ID this_coin_info ;; verified with ASSERT_MY_COIN_ID
next_coin_proof ;; used to generate ASSERT_COIN_ANNOUNCEMENT next_coin_proof ;; used to generate ASSERT_COIN_ANNOUNCEMENT
prev_subtotal ;; included in announcement, prev_coin ASSERT_COIN_ANNOUNCEMENT will fail if wrong prev_subtotal ;; included in announcement, prev_coin ASSERT_COIN_ANNOUNCEMENT will fail if wrong
extra_delta ;; this is the "legal discrepancy" between your real delta and what you're announcing your delta is extra_delta ;; this is the "legal discrepancy" between your real delta and what you're announcing your delta is
) )
;;;;; start library code ;;;;; start library code
(include condition_codes.clvm) (include condition_codes.clvm)
(include curry-and-treehash.clinc) (include curry-and-treehash.clinc)
(include cat_truths.clib) (include cat_truths.clib)
(include utility_macros.clib)
(defconstant ANNOUNCEMENT_MORPH_BYTE 0xca)
(defconstant RING_MORPH_BYTE 0xcb) (defconstant RING_MORPH_BYTE 0xcb)
(defmacro assert items
(if (r items) ; take two lists and merge them into one
(list if (f items) (c assert (r items)) (q . (x))) (defun merge_list (list_a list_b)
(f items) (if list_a
) (c (f list_a) (merge_list (r list_a) list_b))
) list_b
)
(defmacro and ARGS )
(if ARGS
(qq (if (unquote (f ARGS)) ; cat_mod_struct = (MOD_HASH MOD_HASH_hash GENESIS_COIN_CHECKER GENESIS_COIN_CHECKER_hash)
(unquote (c and (r ARGS)))
() (defun-inline mod_hash_from_cat_mod_struct (cat_mod_struct) (f cat_mod_struct))
)) (defun-inline mod_hash_hash_from_cat_mod_struct (cat_mod_struct) (f (r cat_mod_struct)))
1) (defun-inline tail_program_hash_from_cat_mod_struct (cat_mod_struct) (f (r (r cat_mod_struct))))
)
;;;;; end library code
; takes a lisp tree and returns the hash of it
(defun sha256tree1 (TREE) ;; return the puzzle hash for a cat with the given `GENESIS_COIN_CHECKER_hash` & `INNER_PUZZLE`
(if (l TREE) (defun-inline cat_puzzle_hash (cat_mod_struct inner_puzzle_hash)
(sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE))) (puzzle-hash-of-curried-function (mod_hash_from_cat_mod_struct cat_mod_struct)
(sha256 ONE TREE))) inner_puzzle_hash
(sha256 ONE (tail_program_hash_from_cat_mod_struct cat_mod_struct))
; take two lists and merge them into one (mod_hash_hash_from_cat_mod_struct cat_mod_struct)
(defun merge_list (list_a list_b) )
(if list_a )
(c (f list_a) (merge_list (r list_a) list_b))
list_b ;; assert `CREATE_COIN_ANNOUNCEMENT` doesn't contain the RING_MORPH_BYTE bytes so it cannot be used to cheat the coin ring
)
) (defun-inline morph_condition (condition cat_mod_struct)
(if (= (f condition) CREATE_COIN)
; cat_mod_struct = (MOD_HASH MOD_HASH_hash GENESIS_COIN_CHECKER GENESIS_COIN_CHECKER_hash) (c CREATE_COIN
(c (cat_puzzle_hash cat_mod_struct (f (r condition)))
(defun-inline mod_hash_from_cat_mod_struct (cat_mod_struct) (f cat_mod_struct)) (r (r condition)))
(defun-inline mod_hash_hash_from_cat_mod_struct (cat_mod_struct) (f (r cat_mod_struct))) )
(defun-inline tail_program_hash_from_cat_mod_struct (cat_mod_struct) (f (r (r cat_mod_struct)))) (if (= (f condition) CREATE_COIN_ANNOUNCEMENT)
(assert (not (and
;;;;; end library code (= 33 (strlen (f (r condition))))
(= (substr (f (r condition)) 0 ONE) RING_MORPH_BYTE) ; lazy eval
;; return the puzzle hash for a cat with the given `GENESIS_COIN_CHECKER_hash` & `INNER_PUZZLE` ))
(defun-inline cat_puzzle_hash (cat_mod_struct inner_puzzle_hash) ; then
(puzzle-hash-of-curried-function (mod_hash_from_cat_mod_struct cat_mod_struct) condition
inner_puzzle_hash )
(sha256 ONE (tail_program_hash_from_cat_mod_struct cat_mod_struct)) condition
(mod_hash_hash_from_cat_mod_struct cat_mod_struct) )
) )
) )
;; tweak `CREATE_COIN` condition by wrapping the puzzle hash, forcing it to be a cat ;; given a coin's parent, inner_puzzle and amount, and the cat_mod_struct, calculate the id of the coin
;; prepend `CREATE_COIN_ANNOUNCEMENT` with 0xca as bytes so it cannot be used to cheat the coin ring (defun-inline coin_id_for_proof (coin cat_mod_struct)
(calculate_coin_id (f coin) (cat_puzzle_hash cat_mod_struct (f (r coin))) (f (r (r coin))))
(defun-inline morph_condition (condition cat_mod_struct) )
(if (= (f condition) CREATE_COIN)
(c CREATE_COIN ;; utility to fetch coin amount from coin
(c (cat_puzzle_hash cat_mod_struct (f (r condition))) (defun-inline input_amount_for_coin (coin)
(r (r condition))) (f (r (r coin)))
) )
(if (= (f condition) CREATE_COIN_ANNOUNCEMENT)
(c CREATE_COIN_ANNOUNCEMENT ;; calculate the hash of an announcement
(c (sha256 ANNOUNCEMENT_MORPH_BYTE (f (r condition))) ;; we add 0xcb so ring announcements exist in a different namespace to announcements from inner_puzzles
(r (r condition)) (defun-inline calculate_annoucement_id (this_coin_id this_subtotal next_coin_id cat_mod_struct)
) (sha256 next_coin_id RING_MORPH_BYTE (sha256tree (list this_coin_id this_subtotal)))
) )
condition
) ;; create the `ASSERT_COIN_ANNOUNCEMENT` condition that ensures the next coin's announcement is correct
) (defun-inline create_assert_next_announcement_condition (this_coin_id this_subtotal next_coin_id cat_mod_struct)
) (list ASSERT_COIN_ANNOUNCEMENT
(calculate_annoucement_id this_coin_id
;; given a coin's parent, inner_puzzle and amount, and the cat_mod_struct, calculate the id of the coin this_subtotal
(defun-inline coin_id_for_proof (coin cat_mod_struct) next_coin_id
(sha256 (f coin) (cat_puzzle_hash cat_mod_struct (f (r coin))) (f (r (r coin)))) cat_mod_struct
) )
)
;; utility to fetch coin amount from coin )
(defun-inline input_amount_for_coin (coin)
(f (r (r coin))) ;; here we commit to I_{k-1} and S_k
) ;; we add 0xcb so ring announcements exist in a different namespace to announcements from inner_puzzles
(defun-inline create_announcement_condition (prev_coin_id prev_subtotal)
;; calculate the hash of an announcement (list CREATE_COIN_ANNOUNCEMENT
;; we add 0xcb so ring announcements exist in a different namespace to announcements from inner_puzzles (concat RING_MORPH_BYTE (sha256tree (list prev_coin_id prev_subtotal)))
(defun-inline calculate_annoucement_id (this_coin_id this_subtotal next_coin_id cat_mod_struct) )
(sha256 next_coin_id (sha256 RING_MORPH_BYTE this_coin_id this_subtotal)) )
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; create the `ASSERT_COIN_ANNOUNCEMENT` condition that ensures the next coin's announcement is correct
(defun-inline create_assert_next_announcement_condition (this_coin_id this_subtotal next_coin_id cat_mod_struct) ;; this function takes a condition and returns an integer indicating
(list ASSERT_COIN_ANNOUNCEMENT ;; the value of all output coins created with CREATE_COIN. If it's not
(calculate_annoucement_id this_coin_id ;; a CREATE_COIN condition, it returns 0.
this_subtotal
next_coin_id (defun-inline output_value_for_condition (condition)
cat_mod_struct (if (= (f condition) CREATE_COIN)
) (f (r (r condition)))
) 0
) )
)
;; here we commit to I_{k-1} and S_k
;; we add 0xcb so ring announcements exist in a different namespace to announcements from inner_puzzles ;; add two conditions to the list of morphed conditions:
(defun-inline create_announcement_condition (prev_coin_id prev_subtotal) ;; CREATE_COIN_ANNOUNCEMENT for my announcement
(list CREATE_COIN_ANNOUNCEMENT ;; ASSERT_COIN_ANNOUNCEMENT for the next coin's announcement
(sha256 RING_MORPH_BYTE prev_coin_id prev_subtotal) (defun-inline generate_final_output_conditions
) (
) prev_subtotal
this_subtotal
;;;;;;;;;;;;;;;;;;;;;;;;;;; morphed_conditions
prev_coin_id
;; this function takes a condition and returns an integer indicating this_coin_id
;; the value of all output coins created with CREATE_COIN. If it's not next_coin_id
;; a CREATE_COIN condition, it returns 0. cat_mod_struct
)
(defun-inline output_value_for_condition (condition) (c (create_announcement_condition prev_coin_id prev_subtotal)
(if (= (f condition) CREATE_COIN) (c (create_assert_next_announcement_condition this_coin_id this_subtotal next_coin_id cat_mod_struct)
(f (r (r condition))) morphed_conditions)
0 )
) )
)
;; add two conditions to the list of morphed conditions: ;; This next section of code loops through all of the conditions to do three things:
;; CREATE_COIN_ANNOUNCEMENT for my announcement ;; 1) Look for a "magic" value of -113 and, if one exists, filter it, and take note of the tail reveal and solution
;; ASSERT_COIN_ANNOUNCEMENT for the next coin's announcement ;; 2) Morph any CREATE_COIN or CREATE_COIN_ANNOUNCEMENT conditions
(defun-inline generate_final_output_conditions ;; 3) Sum the total output amount of all of the CREATE_COINs that are output by the inner puzzle
( ;;
prev_subtotal ;; After everything return a struct in the format (morphed_conditions . (output_sum . tail_reveal_and_solution))
this_subtotal ;; If multiple magic conditions are specified, the later one will take precedence
morphed_conditions
prev_coin_id (defun-inline condition_tail_reveal (condition) (f (r (r (r condition)))))
this_coin_id (defun-inline condition_tail_solution (condition) (f (r (r (r (r condition))))))
next_coin_id
cat_mod_struct (defun cons_onto_first_and_add_to_second (morphed_condition output_value struct)
) (c (c morphed_condition (f struct)) (c (+ output_value (f (r struct))) (r (r struct))))
(c (create_announcement_condition prev_coin_id prev_subtotal) )
(c (create_assert_next_announcement_condition this_coin_id this_subtotal next_coin_id cat_mod_struct)
morphed_conditions) (defun find_and_strip_tail_info (inner_conditions cat_mod_struct tail_reveal_and_solution)
) (if inner_conditions
) (if (= (output_value_for_condition (f inner_conditions)) -113) ; Checks this is a CREATE_COIN of value -113
(find_and_strip_tail_info
(r inner_conditions)
;; This next section of code loops through all of the conditions to do three things: cat_mod_struct
;; 1) Look for a "magic" value of -113 and, if one exists, filter it, and take note of the tail reveal and solution (c (condition_tail_reveal (f inner_conditions)) (condition_tail_solution (f inner_conditions)))
;; 2) Morph any CREATE_COIN or CREATE_COIN_ANNOUNCEMENT conditions )
;; 3) Sum the total output amount of all of the CREATE_COINs that are output by the inner puzzle (cons_onto_first_and_add_to_second
;; (morph_condition (f inner_conditions) cat_mod_struct)
;; After everything return a struct in the format (morphed_conditions . (output_sum . tail_reveal_and_solution)) (output_value_for_condition (f inner_conditions))
;; If multiple magic conditions are specified, the later one will take precedence (find_and_strip_tail_info
(r inner_conditions)
(defun-inline condition_tail_reveal (condition) (f (r (r (r condition))))) cat_mod_struct
(defun-inline condition_tail_solution (condition) (f (r (r (r (r condition)))))) tail_reveal_and_solution
)
(defun cons_onto_first_and_add_to_second (morphed_condition output_value struct) )
(c (c morphed_condition (f struct)) (c (+ output_value (f (r struct))) (r (r struct)))) )
) (c () (c 0 tail_reveal_and_solution))
)
(defun find_and_strip_tail_info (inner_conditions cat_mod_struct tail_reveal_and_solution) )
(if inner_conditions
(if (= (output_value_for_condition (f inner_conditions)) -113) ; Checks this is a CREATE_COIN of value -113 ;;;;;;;;;;;;;;;;;;;;;;;;;;; lineage checking
(find_and_strip_tail_info
(r inner_conditions) ;; return true iff parent of `this_coin_info` is provably a cat
cat_mod_struct ;; A 'lineage proof' consists of (parent_parent_id parent_INNER_puzzle_hash parent_amount)
(c (condition_tail_reveal (f inner_conditions)) (condition_tail_solution (f inner_conditions))) ;; We use this information to construct a coin who's puzzle has been wrapped in this MOD and verify that,
) ;; once wrapped, it matches our parent coin's ID.
(cons_onto_first_and_add_to_second (defun-inline is_parent_cat (
(morph_condition (f inner_conditions) cat_mod_struct) cat_mod_struct
(output_value_for_condition (f inner_conditions)) parent_id
(find_and_strip_tail_info lineage_proof
(r inner_conditions) )
cat_mod_struct (= parent_id
tail_reveal_and_solution (calculate_coin_id (f lineage_proof)
) (cat_puzzle_hash cat_mod_struct (f (r lineage_proof)))
) (f (r (r lineage_proof)))
) )
(c () (c 0 tail_reveal_and_solution)) )
) )
)
(defun check_lineage_or_run_tail_program
;;;;;;;;;;;;;;;;;;;;;;;;;;; lineage checking (
this_coin_info
;; return true iff parent of `this_coin_info` is provably a cat tail_reveal_and_solution
;; A 'lineage proof' consists of (parent_parent_id parent_INNER_puzzle_hash parent_amount) parent_is_cat ; flag which says whether or not the parent CAT check ran and passed
;; We use this information to construct a coin who's puzzle has been wrapped in this MOD and verify that, lineage_proof
;; once wrapped, it matches our parent coin's ID. Truths
(defun-inline is_parent_cat ( extra_delta
cat_mod_struct inner_conditions
parent_id )
lineage_proof (if tail_reveal_and_solution
) (assert (= (sha256tree (f tail_reveal_and_solution)) (cat_tail_program_hash_truth Truths))
(= parent_id (merge_list
(sha256 (f lineage_proof) (a (f tail_reveal_and_solution)
(cat_puzzle_hash cat_mod_struct (f (r lineage_proof))) (list
(f (r (r lineage_proof))) Truths
) parent_is_cat
) lineage_proof ; Lineage proof is only guaranteed to be true if parent_is_cat
) extra_delta
inner_conditions
(defun check_lineage_or_run_tail_program (r tail_reveal_and_solution)
( )
this_coin_info )
tail_reveal_and_solution inner_conditions
parent_is_cat ; flag which says whether or not the parent CAT check ran and passed )
lineage_proof )
Truths (assert parent_is_cat (not extra_delta)
extra_delta inner_conditions
inner_conditions )
) )
(if tail_reveal_and_solution )
(assert (= (sha256tree1 (f tail_reveal_and_solution)) (cat_tail_program_hash_truth Truths))
(merge_list ;;;;;;;;;;;;;;;;;;;;;;;;;;;
(a (f tail_reveal_and_solution)
(list (defun stager_two (
Truths Truths
parent_is_cat (inner_conditions . (output_sum . tail_reveal_and_solution))
lineage_proof ; Lineage proof is only guaranteed to be true if parent_is_cat lineage_proof
extra_delta prev_coin_id
inner_conditions this_coin_info
(r tail_reveal_and_solution) next_coin_id
) prev_subtotal
) extra_delta
inner_conditions )
) (check_lineage_or_run_tail_program
) this_coin_info
(assert parent_is_cat (not extra_delta) tail_reveal_and_solution
inner_conditions (if lineage_proof (is_parent_cat (cat_struct_truth Truths) (my_parent_cat_truth Truths) lineage_proof) ())
) lineage_proof
) Truths
) extra_delta
(generate_final_output_conditions
;;;;;;;;;;;;;;;;;;;;;;;;;;; prev_subtotal
; the expression on the next line calculates `this_subtotal` by adding the delta to `prev_subtotal`
(defun stager_two ( (+ prev_subtotal (- (input_amount_for_coin this_coin_info) output_sum) extra_delta)
Truths inner_conditions
(inner_conditions . (output_sum . tail_reveal_and_solution)) prev_coin_id
lineage_proof (my_id_cat_truth Truths)
prev_coin_id next_coin_id
this_coin_info (cat_struct_truth Truths)
next_coin_id )
prev_subtotal )
extra_delta )
)
(check_lineage_or_run_tail_program ; CAT TRUTHS struct is: ; CAT Truths is: ((Inner puzzle hash . (MOD hash . (MOD hash hash . TAIL hash))) . (my_id . (my_parent_info my_puzhash my_amount)))
this_coin_info ; create truths - this_coin_info verified true because we calculated my ID from it!
tail_reveal_and_solution ; lineage proof is verified later by cat parent check or tail_program
(if lineage_proof (is_parent_cat (cat_struct_truth Truths) (my_parent_cat_truth Truths) lineage_proof) ())
lineage_proof (defun stager (
Truths cat_mod_struct
extra_delta inner_conditions
(generate_final_output_conditions lineage_proof
prev_subtotal inner_puzzle_hash
; the expression on the next line calculates `this_subtotal` by adding the delta to `prev_subtotal` my_id
(+ prev_subtotal (- (input_amount_for_coin this_coin_info) output_sum) extra_delta) prev_coin_id
inner_conditions this_coin_info
prev_coin_id next_coin_proof
(my_id_cat_truth Truths) prev_subtotal
next_coin_id extra_delta
(cat_struct_truth Truths) )
) (c (list ASSERT_MY_COIN_ID my_id) (stager_two
) (cat_truth_data_to_truth_struct
) inner_puzzle_hash
cat_mod_struct
; CAT TRUTHS struct is: ; CAT Truths is: ((Inner puzzle hash . (MOD hash . (MOD hash hash . TAIL hash))) . (my_id . (my_parent_info my_puzhash my_amount))) my_id
; create truths - this_coin_info verified true because we calculated my ID from it! this_coin_info
; lineage proof is verified later by cat parent check or tail_program )
(find_and_strip_tail_info inner_conditions cat_mod_struct ())
(defun stager ( lineage_proof
cat_mod_struct prev_coin_id
inner_conditions this_coin_info
lineage_proof (coin_id_for_proof next_coin_proof cat_mod_struct)
inner_puzzle_hash prev_subtotal
my_id extra_delta
prev_coin_id ))
this_coin_info )
next_coin_proof
prev_subtotal (stager
extra_delta ;; calculate cat_mod_struct, inner_puzzle_hash, coin_id
) (list MOD_HASH (sha256 ONE MOD_HASH) TAIL_PROGRAM_HASH)
(c (list ASSERT_MY_COIN_ID my_id) (stager_two (a INNER_PUZZLE inner_puzzle_solution)
(cat_truth_data_to_truth_struct lineage_proof
inner_puzzle_hash (sha256tree INNER_PUZZLE)
cat_mod_struct (calculate_coin_id (f this_coin_info) (f (r this_coin_info)) (f (r (r this_coin_info))))
my_id prev_coin_id ; ID
this_coin_info this_coin_info ; (parent_id puzzle_hash amount)
) next_coin_proof ; (parent_id innerpuzhash amount)
(find_and_strip_tail_info inner_conditions cat_mod_struct ()) prev_subtotal
lineage_proof extra_delta
prev_coin_id )
this_coin_info )
(coin_id_for_proof next_coin_proof cat_mod_struct)
prev_subtotal
extra_delta
))
)
(stager
;; calculate cat_mod_struct, inner_puzzle_hash, coin_id
(list MOD_HASH (sha256 ONE MOD_HASH) TAIL_PROGRAM_HASH)
(a INNER_PUZZLE inner_puzzle_solution)
lineage_proof
(sha256tree1 INNER_PUZZLE)
(sha256 (f this_coin_info) (f (r this_coin_info)) (f (r (r this_coin_info))))
prev_coin_id ; ID
this_coin_info ; (parent_id puzzle_hash amount)
next_coin_proof ; (parent_id innerpuzhash amount)
prev_subtotal
extra_delta
)
)

View File

@ -0,0 +1 @@
ff02ffff01ff02ff5effff04ff02ffff04ffff04ff05ffff04ffff0bff34ff0580ffff04ff0bff80808080ffff04ffff02ff17ff2f80ffff04ff5fffff04ffff02ff2effff04ff02ffff04ff17ff80808080ffff04ffff02ff2affff04ff02ffff04ff82027fffff04ff82057fffff04ff820b7fff808080808080ffff04ff81bfffff04ff82017fffff04ff8202ffffff04ff8205ffffff04ff820bffff80808080808080808080808080ffff04ffff01ffffffff3d46ff02ff333cffff0401ff01ff81cb02ffffff20ff02ffff03ff05ffff01ff02ff32ffff04ff02ffff04ff0dffff04ffff0bff7cffff0bff34ff2480ffff0bff7cffff0bff7cffff0bff34ff2c80ff0980ffff0bff7cff0bffff0bff34ff8080808080ff8080808080ffff010b80ff0180ffff02ffff03ffff22ffff09ffff0dff0580ff2280ffff09ffff0dff0b80ff2280ffff15ff17ffff0181ff8080ffff01ff0bff05ff0bff1780ffff01ff088080ff0180ffff02ffff03ff0bffff01ff02ffff03ffff09ffff02ff2effff04ff02ffff04ff13ff80808080ff820b9f80ffff01ff02ff56ffff04ff02ffff04ffff02ff13ffff04ff5fffff04ff17ffff04ff2fffff04ff81bfffff04ff82017fffff04ff1bff8080808080808080ffff04ff82017fff8080808080ffff01ff088080ff0180ffff01ff02ffff03ff17ffff01ff02ffff03ffff20ff81bf80ffff0182017fffff01ff088080ff0180ffff01ff088080ff018080ff0180ff04ffff04ff05ff2780ffff04ffff10ff0bff5780ff778080ffffff02ffff03ff05ffff01ff02ffff03ffff09ffff02ffff03ffff09ff11ff5880ffff0159ff8080ff0180ffff01818f80ffff01ff02ff26ffff04ff02ffff04ff0dffff04ff0bffff04ffff04ff81b9ff82017980ff808080808080ffff01ff02ff7affff04ff02ffff04ffff02ffff03ffff09ff11ff5880ffff01ff04ff58ffff04ffff02ff76ffff04ff02ffff04ff13ffff04ff29ffff04ffff0bff34ff5b80ffff04ff2bff80808080808080ff398080ffff01ff02ffff03ffff09ff11ff7880ffff01ff02ffff03ffff20ffff02ffff03ffff09ffff0121ffff0dff298080ffff01ff02ffff03ffff09ffff0cff29ff80ff3480ff5c80ffff01ff0101ff8080ff0180ff8080ff018080ffff0109ffff01ff088080ff0180ffff010980ff018080ff0180ffff04ffff02ffff03ffff09ff11ff5880ffff0159ff8080ff0180ffff04ffff02ff26ffff04ff02ffff04ff0dffff04ff0bffff04ff17ff808080808080ff80808080808080ff0180ffff01ff04ff80ffff04ff80ff17808080ff0180ffff02ffff03ff05ffff01ff04ff09ffff02ff56ffff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ff0bff7cffff0bff34ff2880ffff0bff7cffff0bff7cffff0bff34ff2c80ff0580ffff0bff7cffff02ff32ffff04ff02ffff04ff07ffff04ffff0bff34ff3480ff8080808080ffff0bff34ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ffff04ffff04ff30ffff04ff5fff808080ffff02ff7effff04ff02ffff04ffff04ffff04ff2fff0580ffff04ff5fff82017f8080ffff04ffff02ff26ffff04ff02ffff04ff0bffff04ff05ffff01ff808080808080ffff04ff17ffff04ff81bfffff04ff82017fffff04ffff02ff2affff04ff02ffff04ff8204ffffff04ffff02ff76ffff04ff02ffff04ff09ffff04ff820affffff04ffff0bff34ff2d80ffff04ff15ff80808080808080ffff04ff8216ffff808080808080ffff04ff8205ffffff04ff820bffff808080808080808080808080ff02ff5affff04ff02ffff04ff5fffff04ff3bffff04ffff02ffff03ff17ffff01ff09ff2dffff02ff2affff04ff02ffff04ff27ffff04ffff02ff76ffff04ff02ffff04ff29ffff04ff57ffff04ffff0bff34ff81b980ffff04ff59ff80808080808080ffff04ff81b7ff80808080808080ff8080ff0180ffff04ff17ffff04ff05ffff04ff8202ffffff04ffff04ffff04ff78ffff04ffff0eff5cffff02ff2effff04ff02ffff04ffff04ff2fffff04ff82017fff808080ff8080808080ff808080ffff04ffff04ff20ffff04ffff0bff81bfff5cffff02ff2effff04ff02ffff04ffff04ff15ffff04ffff10ff82017fffff11ff8202dfff2b80ff8202ff80ff808080ff8080808080ff808080ff138080ff80808080808080808080ff018080

View File

@ -0,0 +1 @@
37bef360ee858133b69d595a906dc45d01af50379dad515eb9518abb7c1d2a7a

View File

@ -2,6 +2,7 @@ import zlib
from typing import List from typing import List
from chia.types.blockchain_format.program import Program
from chia.wallet.puzzles.load_clvm import load_clvm from chia.wallet.puzzles.load_clvm import load_clvm
from chia.wallet.puzzles import p2_delegated_puzzle_or_hidden_puzzle as standard_puzzle from chia.wallet.puzzles import p2_delegated_puzzle_or_hidden_puzzle as standard_puzzle
from chia.wallet.puzzles.cat_loader import CAT_MOD from chia.wallet.puzzles.cat_loader import CAT_MOD
@ -13,16 +14,24 @@ from chia.wallet.nft_wallet.nft_puzzles import (
NFT_TRANSFER_PROGRAM_DEFAULT, NFT_TRANSFER_PROGRAM_DEFAULT,
) )
# Need the legacy CAT mod for zlib backwards compatibility
LEGACY_CAT_MOD = Program.fromhex(
"ff02ffff01ff02ff5effff04ff02ffff04ffff04ff05ffff04ffff0bff2cff0580ffff04ff0bff80808080ffff04ffff02ff17ff2f80ffff04ff5fffff04ffff02ff2effff04ff02ffff04ff17ff80808080ffff04ffff0bff82027fff82057fff820b7f80ffff04ff81bfffff04ff82017fffff04ff8202ffffff04ff8205ffffff04ff820bffff80808080808080808080808080ffff04ffff01ffffffff81ca3dff46ff0233ffff3c04ff01ff0181cbffffff02ff02ffff03ff05ffff01ff02ff32ffff04ff02ffff04ff0dffff04ffff0bff22ffff0bff2cff3480ffff0bff22ffff0bff22ffff0bff2cff5c80ff0980ffff0bff22ff0bffff0bff2cff8080808080ff8080808080ffff010b80ff0180ffff02ffff03ff0bffff01ff02ffff03ffff09ffff02ff2effff04ff02ffff04ff13ff80808080ff820b9f80ffff01ff02ff26ffff04ff02ffff04ffff02ff13ffff04ff5fffff04ff17ffff04ff2fffff04ff81bfffff04ff82017fffff04ff1bff8080808080808080ffff04ff82017fff8080808080ffff01ff088080ff0180ffff01ff02ffff03ff17ffff01ff02ffff03ffff20ff81bf80ffff0182017fffff01ff088080ff0180ffff01ff088080ff018080ff0180ffff04ffff04ff05ff2780ffff04ffff10ff0bff5780ff778080ff02ffff03ff05ffff01ff02ffff03ffff09ffff02ffff03ffff09ff11ff7880ffff0159ff8080ff0180ffff01818f80ffff01ff02ff7affff04ff02ffff04ff0dffff04ff0bffff04ffff04ff81b9ff82017980ff808080808080ffff01ff02ff5affff04ff02ffff04ffff02ffff03ffff09ff11ff7880ffff01ff04ff78ffff04ffff02ff36ffff04ff02ffff04ff13ffff04ff29ffff04ffff0bff2cff5b80ffff04ff2bff80808080808080ff398080ffff01ff02ffff03ffff09ff11ff2480ffff01ff04ff24ffff04ffff0bff20ff2980ff398080ffff010980ff018080ff0180ffff04ffff02ffff03ffff09ff11ff7880ffff0159ff8080ff0180ffff04ffff02ff7affff04ff02ffff04ff0dffff04ff0bffff04ff17ff808080808080ff80808080808080ff0180ffff01ff04ff80ffff04ff80ff17808080ff0180ffffff02ffff03ff05ffff01ff04ff09ffff02ff26ffff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ff0bff22ffff0bff2cff5880ffff0bff22ffff0bff22ffff0bff2cff5c80ff0580ffff0bff22ffff02ff32ffff04ff02ffff04ff07ffff04ffff0bff2cff2c80ff8080808080ffff0bff2cff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bff2cff058080ff0180ffff04ffff04ff28ffff04ff5fff808080ffff02ff7effff04ff02ffff04ffff04ffff04ff2fff0580ffff04ff5fff82017f8080ffff04ffff02ff7affff04ff02ffff04ff0bffff04ff05ffff01ff808080808080ffff04ff17ffff04ff81bfffff04ff82017fffff04ffff0bff8204ffffff02ff36ffff04ff02ffff04ff09ffff04ff820affffff04ffff0bff2cff2d80ffff04ff15ff80808080808080ff8216ff80ffff04ff8205ffffff04ff820bffff808080808080808080808080ff02ff2affff04ff02ffff04ff5fffff04ff3bffff04ffff02ffff03ff17ffff01ff09ff2dffff0bff27ffff02ff36ffff04ff02ffff04ff29ffff04ff57ffff04ffff0bff2cff81b980ffff04ff59ff80808080808080ff81b78080ff8080ff0180ffff04ff17ffff04ff05ffff04ff8202ffffff04ffff04ffff04ff24ffff04ffff0bff7cff2fff82017f80ff808080ffff04ffff04ff30ffff04ffff0bff81bfffff0bff7cff15ffff10ff82017fffff11ff8202dfff2b80ff8202ff808080ff808080ff138080ff80808080808080808080ff018080" # noqa
)
OFFER_MOD = load_clvm("settlement_payments.clvm") OFFER_MOD = load_clvm("settlement_payments.clvm")
# For backwards compatibility to work, we must assume that these mods (already deployed) will not change
# In the case that they do change and we don't support the old asset then we need to keep around the legacy module
ZDICT = [ ZDICT = [
bytes(standard_puzzle.MOD) + bytes(CAT_MOD), bytes(standard_puzzle.MOD) + bytes(LEGACY_CAT_MOD),
bytes(OFFER_MOD), bytes(OFFER_MOD),
bytes(SINGLETON_TOP_LAYER_MOD) bytes(SINGLETON_TOP_LAYER_MOD)
+ bytes(NFT_STATE_LAYER_MOD) + bytes(NFT_STATE_LAYER_MOD)
+ bytes(NFT_OWNERSHIP_LAYER) + bytes(NFT_OWNERSHIP_LAYER)
+ bytes(NFT_METADATA_UPDATER) + bytes(NFT_METADATA_UPDATER)
+ bytes(NFT_TRANSFER_PROGRAM_DEFAULT), + bytes(NFT_TRANSFER_PROGRAM_DEFAULT),
bytes(CAT_MOD),
# more dictionaries go here # more dictionaries go here
] ]

View File

@ -46,7 +46,6 @@ from chia.types.weight_proof import WeightProof
from chia.util.byte_types import hexstr_to_bytes from chia.util.byte_types import hexstr_to_bytes
from chia.util.chunks import chunks from chia.util.chunks import chunks
from chia.util.config import WALLET_PEERS_PATH_KEY_DEPRECATED from chia.util.config import WALLET_PEERS_PATH_KEY_DEPRECATED
from chia.util.default_root import STANDALONE_ROOT_PATH
from chia.util.ints import uint32, uint64 from chia.util.ints import uint32, uint64
from chia.util.keychain import Keychain, KeyringIsLocked from chia.util.keychain import Keychain, KeyringIsLocked
from chia.util.path import path_from_root from chia.util.path import path_from_root
@ -70,6 +69,23 @@ from chia.wallet.wallet_state_manager import WalletStateManager
from chia.wallet.wallet_weight_proof_handler import get_wp_fork_point from chia.wallet.wallet_weight_proof_handler import get_wp_fork_point
def get_wallet_db_path(root_path: Path, config: Dict[str, Any], key_fingerprint: str) -> Path:
"""
Construct a path to the wallet db. Uses config values and the wallet key's fingerprint to
determine the wallet db filename.
"""
db_path_replaced: str = (
config["database_path"].replace("CHALLENGE", config["selected_network"]).replace("KEY", key_fingerprint)
)
# "v2_r1" is the current wallet db version identifier
if "v2_r1" not in db_path_replaced:
db_path_replaced = db_path_replaced.replace("v2", "v2_r1").replace("v1", "v2_r1")
path: Path = path_from_root(root_path, db_path_replaced)
return path
@dataclasses.dataclass @dataclasses.dataclass
class WalletNode: class WalletNode:
config: Dict config: Dict
@ -209,21 +225,9 @@ class WalletNode:
if self.config.get("enable_profiler", False): if self.config.get("enable_profiler", False):
asyncio.create_task(profile_task(self.root_path, "wallet", self.log)) asyncio.create_task(profile_task(self.root_path, "wallet", self.log))
db_path_key_suffix = str(private_key.get_g1().get_fingerprint()) path: Path = get_wallet_db_path(self.root_path, self.config, str(private_key.get_g1().get_fingerprint()))
db_path_replaced: str = (
self.config["database_path"]
.replace("CHALLENGE", self.config["selected_network"])
.replace("KEY", db_path_key_suffix)
)
path = path_from_root(self.root_path, db_path_replaced.replace("v1", "v2"))
path.parent.mkdir(parents=True, exist_ok=True) path.parent.mkdir(parents=True, exist_ok=True)
standalone_path = path_from_root(STANDALONE_ROOT_PATH, f"{db_path_replaced.replace('v2', 'v1')}_new")
if not path.exists():
if standalone_path.exists():
self.log.info(f"Copying wallet db from {standalone_path} to {path}")
path.write_bytes(standalone_path.read_bytes())
self._wallet_state_manager = await WalletStateManager.create( self._wallet_state_manager = await WalletStateManager.create(
private_key, private_key,
self.config, self.config,

View File

@ -10,7 +10,7 @@ from chia.types.blockchain_format.program import Program, SerializedProgram
wallet_program_files = set( wallet_program_files = set(
[ [
"chia/wallet/puzzles/calculate_synthetic_public_key.clvm", "chia/wallet/puzzles/calculate_synthetic_public_key.clvm",
"chia/wallet/puzzles/cat.clvm", "chia/wallet/puzzles/cat_v2.clvm",
"chia/wallet/puzzles/chialisp_deserialisation.clvm", "chia/wallet/puzzles/chialisp_deserialisation.clvm",
"chia/wallet/puzzles/rom_bootstrap_generator.clvm", "chia/wallet/puzzles/rom_bootstrap_generator.clvm",
"chia/wallet/puzzles/generator_for_single_coin.clvm", "chia/wallet/puzzles/generator_for_single_coin.clvm",

View File

@ -83,7 +83,7 @@ class TestPuzzleCompression:
self.compression_factors["unknown_and_standard"] = len(bytes(compressed)) / len(bytes(coin_spend)) self.compression_factors["unknown_and_standard"] = len(bytes(compressed)) / len(bytes(coin_spend))
def test_lowest_best_version(self): def test_lowest_best_version(self):
assert lowest_best_version([bytes(CAT_MOD)]) == 1 assert lowest_best_version([bytes(CAT_MOD)]) == 4
assert lowest_best_version([bytes(OFFER_MOD)]) == 2 assert lowest_best_version([bytes(OFFER_MOD)]) == 2
def test_version_override(self): def test_version_override(self):

View File

@ -2,6 +2,8 @@ import json
from pathlib import Path from pathlib import Path
from typing import List from typing import List
import pytest
from chia.consensus.default_constants import DEFAULT_CONSTANTS from chia.consensus.default_constants import DEFAULT_CONSTANTS
from chia.types.condition_opcodes import ConditionOpcode from chia.types.condition_opcodes import ConditionOpcode
from chia.types.condition_with_args import ConditionWithArgs from chia.types.condition_with_args import ConditionWithArgs
@ -53,6 +55,7 @@ def test_block_no_generator():
assert not cat_list assert not cat_list
@pytest.mark.xfail(reason="Needs update to CAT2")
def test_block_retired_cat_with_memo(): def test_block_retired_cat_with_memo():
dirname = Path(__file__).parent dirname = Path(__file__).parent
with open(dirname / "396963.json") as f: with open(dirname / "396963.json") as f:
@ -73,6 +76,7 @@ def test_block_retired_cat_with_memo():
assert found assert found
@pytest.mark.xfail(reason="Needs update to CAT2")
def test_block_retired_cat_no_memo(): def test_block_retired_cat_no_memo():
dirname = Path(__file__).parent dirname = Path(__file__).parent
with open(dirname / "392111.json") as f: with open(dirname / "392111.json") as f:
@ -94,6 +98,7 @@ def test_block_retired_cat_no_memo():
assert found assert found
@pytest.mark.xfail(reason="Needs update to CAT2")
def test_block_cat(): def test_block_cat():
dirname = Path(__file__).parent dirname = Path(__file__).parent
with open(dirname / "149988.json") as f: with open(dirname / "149988.json") as f:

View File

@ -62,5 +62,10 @@ def test_cat_outer_puzzle() -> None:
ACS, ACS,
inner_solution, inner_solution,
) )
double_cat_puzzle.run(solution) try:
double_cat_puzzle.run(solution)
except Exception as e:
assert e is not None # this should be failing
else:
assert False
assert get_inner_solution(cat_driver, solution) == inner_solution assert get_inner_solution(cat_driver, solution) == inner_solution

View File

@ -781,8 +781,8 @@ async def test_nft_rpc_mint(two_wallet_nodes: Any, trusted: Any) -> None:
"license_uris": license_uris, "license_uris": license_uris,
"license_hash": license_hash, "license_hash": license_hash,
"meta_hash": meta_hash, "meta_hash": meta_hash,
"series_number": sn, "edition_number": sn,
"series_total": st, "edition_total": st,
"meta_uris": meta_uris, "meta_uris": meta_uris,
"royalty_address": royalty_address, "royalty_address": royalty_address,
"target_address": ph, "target_address": ph,

View File

@ -1,6 +1,7 @@
import asyncio import asyncio
import time import time
from typing import List, Tuple from pathlib import Path
from typing import Any, Dict, List, Tuple
import pytest import pytest
@ -18,7 +19,7 @@ from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.compute_memos import compute_memos from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.transaction_type import TransactionType from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.util.wallet_types import AmountWithPuzzlehash from chia.wallet.util.wallet_types import AmountWithPuzzlehash
from chia.wallet.wallet_node import WalletNode from chia.wallet.wallet_node import WalletNode, get_wallet_db_path
from chia.wallet.wallet_state_manager import WalletStateManager from chia.wallet.wallet_state_manager import WalletStateManager
from chia.simulator.block_tools import BlockTools from chia.simulator.block_tools import BlockTools
from tests.pools.test_pool_rpc import wallet_is_synced from tests.pools.test_pool_rpc import wallet_is_synced
@ -893,3 +894,51 @@ class TestWalletSimulator:
await time_out_assert(10, wallet.get_confirmed_balance, funds - AMOUNT_TO_SEND) await time_out_assert(10, wallet.get_confirmed_balance, funds - AMOUNT_TO_SEND)
await time_out_assert(10, wallet.get_unconfirmed_balance, funds - AMOUNT_TO_SEND) await time_out_assert(10, wallet.get_unconfirmed_balance, funds - AMOUNT_TO_SEND)
def test_get_wallet_db_path_v2_r1() -> None:
root_path: Path = Path("/x/y/z/.chia/mainnet").resolve()
config: Dict[str, Any] = {
"database_path": "wallet/db/blockchain_wallet_v2_r1_CHALLENGE_KEY.sqlite",
"selected_network": "mainnet",
}
fingerprint: str = "1234567890"
wallet_db_path: Path = get_wallet_db_path(root_path, config, fingerprint)
assert wallet_db_path == root_path.joinpath("wallet/db/blockchain_wallet_v2_r1_mainnet_1234567890.sqlite")
def test_get_wallet_db_path_v2() -> None:
root_path: Path = Path("/x/y/z/.chia/mainnet").resolve()
config: Dict[str, Any] = {
"database_path": "wallet/db/blockchain_wallet_v2_CHALLENGE_KEY.sqlite",
"selected_network": "mainnet",
}
fingerprint: str = "1234567890"
wallet_db_path: Path = get_wallet_db_path(root_path, config, fingerprint)
assert wallet_db_path == root_path.joinpath("wallet/db/blockchain_wallet_v2_r1_mainnet_1234567890.sqlite")
def test_get_wallet_db_path_v1() -> None:
root_path: Path = Path("/x/y/z/.chia/mainnet").resolve()
config: Dict[str, Any] = {
"database_path": "wallet/db/blockchain_wallet_v1_CHALLENGE_KEY.sqlite",
"selected_network": "mainnet",
}
fingerprint: str = "1234567890"
wallet_db_path: Path = get_wallet_db_path(root_path, config, fingerprint)
assert wallet_db_path == root_path.joinpath("wallet/db/blockchain_wallet_v2_r1_mainnet_1234567890.sqlite")
def test_get_wallet_db_path_testnet() -> None:
root_path: Path = Path("/x/y/z/.chia/testnet").resolve()
config: Dict[str, Any] = {
"database_path": "wallet/db/blockchain_wallet_v2_CHALLENGE_KEY.sqlite",
"selected_network": "testnet",
}
fingerprint: str = "1234567890"
wallet_db_path: Path = get_wallet_db_path(root_path, config, fingerprint)
assert wallet_db_path == root_path.joinpath("wallet/db/blockchain_wallet_v2_r1_testnet_1234567890.sqlite")