chia-blockchain/chia/wallet/wallet.py

447 lines
18 KiB
Python
Raw Normal View History

2020-11-11 20:22:29 +03:00
import logging
2020-04-28 04:42:08 +03:00
import time
from typing import Any, Dict, List, Optional, Set
2020-11-11 20:22:29 +03:00
from blspy import G1Element
2020-11-11 20:22:29 +03:00
2021-04-17 09:13:22 +03:00
from chia.consensus.cost_calculator import calculate_cost_of_program, NPCResult
from chia.full_node.bundle_tools import simple_solution_generator
from chia.full_node.mempool_check_conditions import get_name_puzzle_conditions
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.program import Program
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.coin_solution import CoinSolution
2021-04-17 09:13:22 +03:00
from chia.types.generator_types import BlockGenerator
from chia.types.spend_bundle import SpendBundle
from chia.util.ints import uint8, uint32, uint64, uint128
from chia.wallet.derivation_record import DerivationRecord
from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import (
2020-11-11 20:22:29 +03:00
DEFAULT_HIDDEN_PUZZLE_HASH,
calculate_synthetic_secret_key,
puzzle_for_pk,
solution_for_conditions,
2020-09-17 02:41:06 +03:00
)
from chia.wallet.puzzles.puzzle_utils import (
make_assert_coin_announcement,
make_assert_puzzle_announcement,
2020-02-13 22:57:40 +03:00
make_assert_my_coin_id_condition,
make_assert_absolute_seconds_exceeds_condition,
make_create_coin_announcement,
make_create_puzzle_announcement,
2020-02-13 22:57:40 +03:00
make_create_coin_condition,
make_reserve_fee_condition,
2020-04-20 08:10:19 +03:00
)
from chia.wallet.secret_key_store import SecretKeyStore
from chia.wallet.sign_coin_solutions import sign_coin_solutions
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet_coin_record import WalletCoinRecord
from chia.wallet.wallet_info import WalletInfo
2020-02-24 20:16:47 +03:00
2020-02-12 00:00:41 +03:00
2020-09-24 03:06:42 +03:00
class Wallet:
wallet_state_manager: Any
2020-02-13 22:57:40 +03:00
log: logging.Logger
wallet_id: uint32
secret_key_store: SecretKeyStore
cost_of_single_tx: Optional[int]
2020-02-13 23:59:03 +03:00
2020-02-13 22:57:40 +03:00
@staticmethod
2020-02-24 21:41:54 +03:00
async def create(
2020-09-15 19:56:04 +03:00
wallet_state_manager: Any,
info: WalletInfo,
name: str = None,
2020-02-24 21:41:54 +03:00
):
2020-02-13 22:57:40 +03:00
self = Wallet()
2020-02-12 00:00:41 +03:00
if name:
self.log = logging.getLogger(name)
else:
self.log = logging.getLogger(__name__)
2020-02-24 20:16:47 +03:00
self.wallet_state_manager = wallet_state_manager
self.wallet_id = info.id
self.secret_key_store = SecretKeyStore()
self.cost_of_single_tx = None
2020-02-13 22:57:40 +03:00
return self
2020-02-12 04:01:39 +03:00
async def get_max_send_amount(self, records=None):
spendable: List[WalletCoinRecord] = list(
await self.wallet_state_manager.get_spendable_coins_for_wallet(self.id(), records)
)
if len(spendable) == 0:
return 0
spendable.sort(reverse=True, key=lambda record: record.coin.amount)
if self.cost_of_single_tx is None:
coin = spendable[0].coin
tx = await self.generate_signed_transaction(
coin.amount, coin.puzzle_hash, coins={coin}, ignore_max_send_amount=True
)
2021-04-17 09:13:22 +03:00
program: BlockGenerator = simple_solution_generator(tx.spend_bundle)
# npc contains names of the coins removed, puzzle_hashes and their spend conditions
result: NPCResult = get_name_puzzle_conditions(
program, self.wallet_state_manager.constants.MAX_BLOCK_COST_CLVM, True
)
2021-04-17 09:13:22 +03:00
cost_result: uint64 = calculate_cost_of_program(
program.program, result, self.wallet_state_manager.constants.COST_PER_BYTE
)
2021-04-17 09:13:22 +03:00
self.cost_of_single_tx = cost_result
self.log.info(f"Cost of a single tx for standard wallet: {self.cost_of_single_tx}")
max_cost = self.wallet_state_manager.constants.MAX_BLOCK_COST_CLVM / 2 # avoid full block TXs
current_cost = 0
total_amount = 0
total_coin_count = 0
for record in spendable:
current_cost += self.cost_of_single_tx
total_amount += record.coin.amount
total_coin_count += 1
if current_cost + self.cost_of_single_tx > max_cost:
break
return total_amount
2020-09-24 03:47:06 +03:00
@classmethod
def type(cls) -> uint8:
return uint8(WalletType.STANDARD_WALLET)
def id(self) -> uint32:
return self.wallet_id
2020-09-24 03:47:06 +03:00
2021-02-11 06:53:38 +03:00
async def get_confirmed_balance(self, unspent_records=None) -> uint128:
2021-01-16 07:04:34 +03:00
return await self.wallet_state_manager.get_confirmed_balance_for_wallet(self.id(), unspent_records)
2020-02-13 22:57:40 +03:00
2021-02-11 06:53:38 +03:00
async def get_unconfirmed_balance(self, unspent_records=None) -> uint128:
2021-01-16 07:04:34 +03:00
return await self.wallet_state_manager.get_unconfirmed_balance(self.id(), unspent_records)
2020-02-13 23:59:03 +03:00
2021-02-11 06:53:38 +03:00
async def get_spendable_balance(self, unspent_records=None) -> uint128:
2021-01-16 07:04:34 +03:00
spendable = await self.wallet_state_manager.get_confirmed_spendable_balance_for_wallet(
self.id(), unspent_records
)
return spendable
Electron react (#226) * clean react * add material ui * add word list * mnemonic v0 * jeepney backup * keychain usage * wallet api * mnemonic ui * mnemonics redux state * handle exceptions correctly * dashboard * wallets * get puzzle hash * tx history * sidebar * start stop wallet node * use existing mnemonics * status info * create cc wallet * theme should be outside of switch * create offer * dbus alternative for linux * key migration * don't autocomplete, don't reset simulator db * reset mnemonics * Refactor keychain, and key migration * Implement UI for changing keys * Removing keys and mnemonic button * Start making farmer and harvester RPCs * start rpx for simulator * Harvester and farmer websocket, and basic UI * Plot display and deletion * launch daemon on start * State changes from full node, harvester, farmer, and full node ui improvements * split balances in react * pending change balance * plotter * dev config * maintain connection / retry * Remove electron-ui, and style fixes * Better farmer and full node control * Remove electron ui references * Uncomment out starting the dameon * Remove timelord tab, and change full node style * Clean up new wallet login * Refactor RPCs * Now that the GH runner uses python 3.7.7 - use for windows installer * add balance split to coloured coin wallet * spendable balance fix * Import private key from UI fix * mac build/installer Co-authored-by: Mariano Sorgente <sorgente711@gmail.com> Co-authored-by: Lipa Long <lipa@chia.net> Co-authored-by: Gene Hoffman <hoffmang@hoffmang.com>
2020-05-20 10:41:10 +03:00
async def get_pending_change_balance(self) -> uint64:
2020-12-11 10:27:03 +03:00
unconfirmed_tx = await self.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(self.id())
Electron react (#226) * clean react * add material ui * add word list * mnemonic v0 * jeepney backup * keychain usage * wallet api * mnemonic ui * mnemonics redux state * handle exceptions correctly * dashboard * wallets * get puzzle hash * tx history * sidebar * start stop wallet node * use existing mnemonics * status info * create cc wallet * theme should be outside of switch * create offer * dbus alternative for linux * key migration * don't autocomplete, don't reset simulator db * reset mnemonics * Refactor keychain, and key migration * Implement UI for changing keys * Removing keys and mnemonic button * Start making farmer and harvester RPCs * start rpx for simulator * Harvester and farmer websocket, and basic UI * Plot display and deletion * launch daemon on start * State changes from full node, harvester, farmer, and full node ui improvements * split balances in react * pending change balance * plotter * dev config * maintain connection / retry * Remove electron-ui, and style fixes * Better farmer and full node control * Remove electron ui references * Uncomment out starting the dameon * Remove timelord tab, and change full node style * Clean up new wallet login * Refactor RPCs * Now that the GH runner uses python 3.7.7 - use for windows installer * add balance split to coloured coin wallet * spendable balance fix * Import private key from UI fix * mac build/installer Co-authored-by: Mariano Sorgente <sorgente711@gmail.com> Co-authored-by: Lipa Long <lipa@chia.net> Co-authored-by: Gene Hoffman <hoffmang@hoffmang.com>
2020-05-20 10:41:10 +03:00
addition_amount = 0
for record in unconfirmed_tx:
if not record.is_in_mempool():
continue
Electron react (#226) * clean react * add material ui * add word list * mnemonic v0 * jeepney backup * keychain usage * wallet api * mnemonic ui * mnemonics redux state * handle exceptions correctly * dashboard * wallets * get puzzle hash * tx history * sidebar * start stop wallet node * use existing mnemonics * status info * create cc wallet * theme should be outside of switch * create offer * dbus alternative for linux * key migration * don't autocomplete, don't reset simulator db * reset mnemonics * Refactor keychain, and key migration * Implement UI for changing keys * Removing keys and mnemonic button * Start making farmer and harvester RPCs * start rpx for simulator * Harvester and farmer websocket, and basic UI * Plot display and deletion * launch daemon on start * State changes from full node, harvester, farmer, and full node ui improvements * split balances in react * pending change balance * plotter * dev config * maintain connection / retry * Remove electron-ui, and style fixes * Better farmer and full node control * Remove electron ui references * Uncomment out starting the dameon * Remove timelord tab, and change full node style * Clean up new wallet login * Refactor RPCs * Now that the GH runner uses python 3.7.7 - use for windows installer * add balance split to coloured coin wallet * spendable balance fix * Import private key from UI fix * mac build/installer Co-authored-by: Mariano Sorgente <sorgente711@gmail.com> Co-authored-by: Lipa Long <lipa@chia.net> Co-authored-by: Gene Hoffman <hoffmang@hoffmang.com>
2020-05-20 10:41:10 +03:00
our_spend = False
for coin in record.removals:
2020-12-11 10:27:03 +03:00
if await self.wallet_state_manager.does_coin_belong_to_wallet(coin, self.id()):
Electron react (#226) * clean react * add material ui * add word list * mnemonic v0 * jeepney backup * keychain usage * wallet api * mnemonic ui * mnemonics redux state * handle exceptions correctly * dashboard * wallets * get puzzle hash * tx history * sidebar * start stop wallet node * use existing mnemonics * status info * create cc wallet * theme should be outside of switch * create offer * dbus alternative for linux * key migration * don't autocomplete, don't reset simulator db * reset mnemonics * Refactor keychain, and key migration * Implement UI for changing keys * Removing keys and mnemonic button * Start making farmer and harvester RPCs * start rpx for simulator * Harvester and farmer websocket, and basic UI * Plot display and deletion * launch daemon on start * State changes from full node, harvester, farmer, and full node ui improvements * split balances in react * pending change balance * plotter * dev config * maintain connection / retry * Remove electron-ui, and style fixes * Better farmer and full node control * Remove electron ui references * Uncomment out starting the dameon * Remove timelord tab, and change full node style * Clean up new wallet login * Refactor RPCs * Now that the GH runner uses python 3.7.7 - use for windows installer * add balance split to coloured coin wallet * spendable balance fix * Import private key from UI fix * mac build/installer Co-authored-by: Mariano Sorgente <sorgente711@gmail.com> Co-authored-by: Lipa Long <lipa@chia.net> Co-authored-by: Gene Hoffman <hoffmang@hoffmang.com>
2020-05-20 10:41:10 +03:00
our_spend = True
break
if our_spend is not True:
continue
for coin in record.additions:
2020-12-11 10:27:03 +03:00
if await self.wallet_state_manager.does_coin_belong_to_wallet(coin, self.id()):
Electron react (#226) * clean react * add material ui * add word list * mnemonic v0 * jeepney backup * keychain usage * wallet api * mnemonic ui * mnemonics redux state * handle exceptions correctly * dashboard * wallets * get puzzle hash * tx history * sidebar * start stop wallet node * use existing mnemonics * status info * create cc wallet * theme should be outside of switch * create offer * dbus alternative for linux * key migration * don't autocomplete, don't reset simulator db * reset mnemonics * Refactor keychain, and key migration * Implement UI for changing keys * Removing keys and mnemonic button * Start making farmer and harvester RPCs * start rpx for simulator * Harvester and farmer websocket, and basic UI * Plot display and deletion * launch daemon on start * State changes from full node, harvester, farmer, and full node ui improvements * split balances in react * pending change balance * plotter * dev config * maintain connection / retry * Remove electron-ui, and style fixes * Better farmer and full node control * Remove electron ui references * Uncomment out starting the dameon * Remove timelord tab, and change full node style * Clean up new wallet login * Refactor RPCs * Now that the GH runner uses python 3.7.7 - use for windows installer * add balance split to coloured coin wallet * spendable balance fix * Import private key from UI fix * mac build/installer Co-authored-by: Mariano Sorgente <sorgente711@gmail.com> Co-authored-by: Lipa Long <lipa@chia.net> Co-authored-by: Gene Hoffman <hoffmang@hoffmang.com>
2020-05-20 10:41:10 +03:00
addition_amount += coin.amount
return uint64(addition_amount)
def puzzle_for_pk(self, pubkey: bytes) -> Program:
2020-02-12 04:01:39 +03:00
return puzzle_for_pk(pubkey)
2020-12-11 10:27:03 +03:00
async def hack_populate_secret_key_for_puzzle_hash(self, puzzle_hash: bytes32) -> G1Element:
maybe = await self.wallet_state_manager.get_keys(puzzle_hash)
if maybe is None:
error_msg = f"Wallet couldn't find keys for puzzle_hash {puzzle_hash}"
self.log.error(error_msg)
raise ValueError(error_msg)
# Get puzzle for pubkey
public_key, secret_key = maybe
# HACK
2020-12-11 10:27:03 +03:00
synthetic_secret_key = calculate_synthetic_secret_key(secret_key, DEFAULT_HIDDEN_PUZZLE_HASH)
2020-11-11 20:22:29 +03:00
self.secret_key_store.save_secret_key(synthetic_secret_key)
2020-09-17 01:53:22 +03:00
return public_key
2020-12-11 10:27:03 +03:00
async def hack_populate_secret_keys_for_coin_solutions(self, coin_solutions: List[CoinSolution]) -> None:
"""
This hack forces secret keys into the `_pk2sk` lookup. This should eventually be replaced
by a persistent DB table that can do this look-up directly.
"""
for coin_solution in coin_solutions:
2020-12-11 10:27:03 +03:00
await self.hack_populate_secret_key_for_puzzle_hash(coin_solution.coin.puzzle_hash)
2020-09-17 01:53:22 +03:00
async def puzzle_for_puzzle_hash(self, puzzle_hash: bytes32) -> Program:
public_key = await self.hack_populate_secret_key_for_puzzle_hash(puzzle_hash)
return puzzle_for_pk(bytes(public_key))
2020-04-10 17:53:31 +03:00
async def get_new_puzzle(self) -> Program:
dr = await self.wallet_state_manager.get_unused_derivation_record(self.id())
2020-08-13 03:08:05 +03:00
return puzzle_for_pk(bytes(dr.pubkey))
2020-04-10 17:53:31 +03:00
async def get_puzzle_hash(self, new: bool):
if new:
return await self.get_new_puzzlehash()
else:
record: Optional[
DerivationRecord
] = await self.wallet_state_manager.get_current_derivation_record_for_wallet(self.id())
if record is None:
return await self.get_new_puzzlehash()
return record.puzzle_hash
async def get_new_puzzlehash(self) -> bytes32:
2020-12-11 10:27:03 +03:00
return (await self.wallet_state_manager.get_unused_derivation_record(self.id())).puzzle_hash
2020-02-12 04:01:39 +03:00
def make_solution(
self,
primaries: Optional[List[Dict[str, Any]]] = None,
min_time=0,
me=None,
coin_announcements=None,
coin_announcements_to_assert=None,
puzzle_announcements=None,
puzzle_announcements_to_assert=None,
fee=0,
2021-02-21 22:24:57 +03:00
) -> Program:
2020-09-16 03:09:17 +03:00
assert fee >= 0
2020-03-06 02:53:36 +03:00
condition_list = []
2020-02-13 22:57:40 +03:00
if primaries:
for primary in primaries:
2020-12-11 10:27:03 +03:00
condition_list.append(make_create_coin_condition(primary["puzzlehash"], primary["amount"]))
2020-02-12 04:01:39 +03:00
if min_time > 0:
condition_list.append(make_assert_absolute_seconds_exceeds_condition(min_time))
2020-02-12 04:01:39 +03:00
if me:
2020-03-06 02:53:36 +03:00
condition_list.append(make_assert_my_coin_id_condition(me["id"]))
2020-04-20 08:08:16 +03:00
if fee:
condition_list.append(make_reserve_fee_condition(fee))
if coin_announcements:
for announcement in coin_announcements:
condition_list.append(make_create_coin_announcement(announcement))
if coin_announcements_to_assert:
for announcement_hash in coin_announcements_to_assert:
condition_list.append(make_assert_coin_announcement(announcement_hash))
if puzzle_announcements:
for announcement in puzzle_announcements:
condition_list.append(make_create_puzzle_announcement(announcement))
if puzzle_announcements_to_assert:
for announcement_hash in puzzle_announcements_to_assert:
condition_list.append(make_assert_puzzle_announcement(announcement_hash))
2020-09-17 02:31:30 +03:00
return solution_for_conditions(condition_list)
2020-02-12 04:01:39 +03:00
2020-09-14 12:29:03 +03:00
async def select_coins(self, amount, exclude: List[Coin] = None) -> Set[Coin]:
2020-03-19 11:26:51 +03:00
""" Returns a set of coins that can be used for generating a new transaction. """
async with self.wallet_state_manager.lock:
2020-04-22 08:59:48 +03:00
if exclude is None:
exclude = []
2020-06-11 07:30:33 +03:00
spendable_amount = await self.get_spendable_balance()
2020-03-19 11:26:51 +03:00
2020-06-11 07:30:33 +03:00
if amount > spendable_amount:
2020-09-14 12:29:03 +03:00
error_msg = (
2020-09-14 15:06:41 +03:00
f"Can't select amount higher than our spendable balance. Amount: {amount}, spendable: "
2020-09-14 12:29:03 +03:00
f" {spendable_amount}"
)
2020-09-14 12:29:03 +03:00
self.log.warning(error_msg)
raise ValueError(error_msg)
2020-03-19 11:26:51 +03:00
self.log.info(f"About to select coins for amount {amount}")
unspent: List[WalletCoinRecord] = list(
2020-12-11 10:27:03 +03:00
await self.wallet_state_manager.get_spendable_coins_for_wallet(self.id())
2020-04-02 20:33:38 +03:00
)
sum_value = 0
used_coins: Set = set()
# Use older coins first
unspent.sort(reverse=True, key=lambda r: r.coin.amount)
# Try to use coins from the store, if there isn't enough of "unused"
# coins use change coins that are not confirmed yet
2020-12-11 10:27:03 +03:00
unconfirmed_removals: Dict[bytes32, Coin] = await self.wallet_state_manager.unconfirmed_removals_for_wallet(
self.id()
2020-03-28 00:03:48 +03:00
)
for coinrecord in unspent:
if sum_value >= amount and len(used_coins) > 0:
2020-03-19 11:26:51 +03:00
break
if coinrecord.coin.name() in unconfirmed_removals:
2020-03-19 11:26:51 +03:00
continue
2020-04-22 08:59:48 +03:00
if coinrecord.coin in exclude:
continue
sum_value += coinrecord.coin.amount
used_coins.add(coinrecord.coin)
self.log.debug(
f"Selected coin: {coinrecord.coin.name()} at height {coinrecord.confirmed_block_height}!"
)
2020-03-28 00:03:48 +03:00
# This happens when we couldn't use one of the coins because it's already used
# but unconfirmed, and we are waiting for the change. (unconfirmed_additions)
if sum_value < amount:
raise ValueError(
"Can't make this transaction at the moment. Waiting for the change from the previous transaction."
)
2020-12-11 21:44:15 +03:00
self.log.debug(f"Successfully selected coins: {used_coins}")
return used_coins
2020-03-19 11:26:51 +03:00
2020-02-13 22:57:40 +03:00
async def generate_unsigned_transaction(
2020-03-23 22:59:53 +03:00
self,
amount: uint64,
2020-03-23 22:59:53 +03:00
newpuzzlehash: bytes32,
fee: uint64 = uint64(0),
2020-03-23 22:59:53 +03:00
origin_id: bytes32 = None,
coins: Set[Coin] = None,
primaries_input: Optional[List[Dict[str, Any]]] = None,
ignore_max_send_amount: bool = False,
) -> List[CoinSolution]:
2020-03-06 02:53:36 +03:00
"""
Generates a unsigned transaction in form of List(Puzzle, Solutions)
"""
if primaries_input is None:
primaries = None
total_amount = amount + fee
else:
primaries = primaries_input.copy()
primaries_amount = 0
for prim in primaries:
primaries_amount += prim["amount"]
total_amount = amount + fee + primaries_amount
if not ignore_max_send_amount:
max_send = await self.get_max_send_amount()
if total_amount > max_send:
raise ValueError(f"Can't send more than {max_send} in a single transaction")
if coins is None:
coins = await self.select_coins(total_amount)
2020-09-14 12:29:03 +03:00
assert len(coins) > 0
2020-03-06 02:53:36 +03:00
2020-04-01 04:59:14 +03:00
self.log.info(f"coins is not None {coins}")
spend_value = sum([coin.amount for coin in coins])
change = spend_value - total_amount
2020-03-06 02:53:36 +03:00
spends: List[CoinSolution] = []
2020-03-06 02:53:36 +03:00
output_created = False
for coin in coins:
2020-04-01 04:59:14 +03:00
self.log.info(f"coin from coins {coin}")
puzzle: Program = await self.puzzle_for_puzzle_hash(coin.puzzle_hash)
2020-03-06 02:53:36 +03:00
# Only one coin creates outputs
if not output_created and origin_id in (None, coin.name()):
if primaries is None:
primaries = [{"puzzlehash": newpuzzlehash, "amount": amount}]
else:
primaries.append({"puzzlehash": newpuzzlehash, "amount": amount})
2020-02-12 04:01:39 +03:00
if change > 0:
changepuzzlehash = await self.get_new_puzzlehash()
2020-02-13 22:57:40 +03:00
primaries.append({"puzzlehash": changepuzzlehash, "amount": change})
2020-09-16 03:09:17 +03:00
solution = self.make_solution(primaries=primaries, fee=fee)
2020-02-12 04:01:39 +03:00
output_created = True
else:
2020-04-20 08:08:16 +03:00
solution = self.make_solution()
2020-03-06 02:53:36 +03:00
2021-02-21 22:24:57 +03:00
spends.append(CoinSolution(coin, puzzle, solution))
2020-04-01 04:59:14 +03:00
self.log.info(f"Spends is {spends}")
2020-02-12 04:01:39 +03:00
return spends
2020-09-17 02:41:06 +03:00
async def sign_transaction(self, coin_solutions: List[CoinSolution]) -> SpendBundle:
return await sign_coin_solutions(
coin_solutions,
self.secret_key_store.secret_key_for_public_key,
self.wallet_state_manager.constants.AGG_SIG_ME_ADDITIONAL_DATA,
self.wallet_state_manager.constants.MAX_BLOCK_COST_CLVM,
)
2020-02-13 22:57:40 +03:00
async def generate_signed_transaction(
2020-03-23 22:59:53 +03:00
self,
amount: uint64,
puzzle_hash: bytes32,
fee: uint64 = uint64(0),
2020-03-23 22:59:53 +03:00
origin_id: bytes32 = None,
coins: Set[Coin] = None,
primaries: Optional[List[Dict[str, bytes32]]] = None,
ignore_max_send_amount: bool = False,
2020-09-14 12:29:03 +03:00
) -> TransactionRecord:
2020-02-25 04:19:50 +03:00
""" Use this to generate transaction. """
if primaries is None:
non_change_amount = amount
else:
non_change_amount = uint64(amount + sum(p["amount"] for p in primaries))
2020-03-19 11:26:51 +03:00
transaction = await self.generate_unsigned_transaction(
amount, puzzle_hash, fee, origin_id, coins, primaries, ignore_max_send_amount
)
2020-09-14 12:29:03 +03:00
assert len(transaction) > 0
2020-04-01 04:59:14 +03:00
2020-04-01 07:00:49 +03:00
self.log.info("About to sign a transaction")
await self.hack_populate_secret_keys_for_coin_solutions(transaction)
spend_bundle: SpendBundle = await sign_coin_solutions(
transaction,
self.secret_key_store.secret_key_for_public_key,
self.wallet_state_manager.constants.AGG_SIG_ME_ADDITIONAL_DATA,
self.wallet_state_manager.constants.MAX_BLOCK_COST_CLVM,
)
2020-02-13 22:57:40 +03:00
2020-04-28 04:42:08 +03:00
now = uint64(int(time.time()))
add_list: List[Coin] = list(spend_bundle.additions())
rem_list: List[Coin] = list(spend_bundle.removals())
assert sum(a.amount for a in add_list) + fee == sum(r.amount for r in rem_list)
2020-04-28 04:42:08 +03:00
2020-09-14 12:29:03 +03:00
return TransactionRecord(
2021-01-08 07:49:15 +03:00
confirmed_at_height=uint32(0),
2020-04-28 04:42:08 +03:00
created_at_time=now,
to_puzzle_hash=puzzle_hash,
amount=uint64(non_change_amount),
2020-04-28 04:42:08 +03:00
fee_amount=uint64(fee),
confirmed=False,
sent=uint32(0),
spend_bundle=spend_bundle,
additions=add_list,
removals=rem_list,
wallet_id=self.id(),
2020-04-28 04:42:08 +03:00
sent_to=[],
2020-06-12 02:24:10 +03:00
trade_id=None,
Ui farm (#537) * added farm cards * updated farming page updated card, accordion and table components * updated formating * added @chia/core and @chia/icons packages small refactoring * replaced brand with chia icon removed modal dialog * removed old pages added WalletType into the constants * added craco for local alias fixed typos * fixed app provdier and typos * eslint format * updated deps * added minimum K=32 for mainnet added precision = 3 for plot size and total net size refactored plot page added hooks for open and select directory via electron api added react-form-hooks components for material-ui * updated format of the code * fix simulator * black * deps * added plot list * removed unused components moved plot list from farmer into the plot page removed unused console.logs updated format for fee, reward and total number * Bump colorlog to 4.5.0 * Bump colorlog to 4.6.2 * Farm crash fixes (#512) * Bump blspy to 0.2.5 Incorporate @wjblanke's potential bls fix for farming crashes * blspy to 0.2.6 * move to blspy 0.2.7 * added tooltip into the table cell fixed list of the plots added farming visualisation and hook for the farming state * renamed back index to selectKey * transaction type * Bump cbor2 from 5.1.2 to 5.2.0 Bumps [cbor2](https://github.com/agronholm/cbor2) from 5.1.2 to 5.2.0. - [Release notes](https://github.com/agronholm/cbor2/releases) - [Changelog](https://github.com/agronholm/cbor2/blob/master/docs/versionhistory.rst) - [Commits](https://github.com/agronholm/cbor2/compare/5.1.2...5.2.0) Signed-off-by: dependabot[bot] <support@github.com> * Add cbor 5.2.0 to install.sh * Don't forget azure pipelines * Bump sortedcontainers from 2.2.2 to 2.3.0 Bumps [sortedcontainers](https://github.com/grantjenks/python-sortedcontainers) from 2.2.2 to 2.3.0. - [Release notes](https://github.com/grantjenks/python-sortedcontainers/releases) - [Changelog](https://github.com/grantjenks/python-sortedcontainers/blob/master/HISTORY.rst) - [Commits](https://github.com/grantjenks/python-sortedcontainers/compare/v2.2.2...v2.3.0) Signed-off-by: dependabot[bot] <support@github.com> * Bump clvm-tools from 0.1.6 to 0.1.7 Bumps [clvm-tools](https://github.com/Chia-Network/clvm_tools) from 0.1.6 to 0.1.7. - [Release notes](https://github.com/Chia-Network/clvm_tools/releases) - [Commits](https://github.com/Chia-Network/clvm_tools/compare/0.1.6...0.1.7) Signed-off-by: dependabot[bot] <support@github.com> * Have Cbor2 version only rely on setup.py (#518) * cbor2 version should only be in setup.py * Build and install wheels in one step on Azure * swapped standard puzzle to use aggsig_me fixed bug in sign_coin_solutions where aggsig_me would not be signed correctly * cc_wallet and trade_manager use aggsig_me * fixed aggsig_me bug in wallet_tool * appeased superlinter black requests * added aggsig_me to cost_calculator, same as aggsig * black fix cost calculator * Bump chiapos to 0.12.35, catch up changelog * Appease the markdown lint * used new type enum from transaction simplified modals and added new type of modals * updated format of the UI files * added failed and not found plots fixed plot header added delete action for plot * typo * fixed scroll bar in the wallets list * removed unused code and fixed windows build * fixed all known scroll bar issues * added layout sidebar simplified layout flexbox * added radio button to chia/core added box shadow for layout sidebar showed plot in parallel (disabled until we add support) * npm run buil * removed additional fields from queue item * first version of refactored trade part * call get_plots after harvester updated format removed unused console.logs * added plot queue * upnp * Bump pos/vdf/bip158/bls for python 3.9 wheels * downgrade to last good chiavdf - no 3.9 ubuntu yet * Build python 3.8 and 3.9 on MacOS - temporarily compile chiavdf on Mac * Don't build vdf_client at first on Mac 3.9 * Modify typing for python 3.9 (#532) * Give MacOS 3.9 more time to test * try get_args * 3.7 * sys * tuple * is not none * pretty printer versus flake * black * Revert MacOS testing time to 60m max Co-authored-by: Gene Hoffman <hoffmang@hoffmang.com> Co-authored-by: Gene Hoffman <30377676+hoffmang9@users.noreply.github.com> * Bump concurrent-log-handler from 0.9.17 to 0.9.19 (#530) Bumps [concurrent-log-handler](https://github.com/Preston-Landers/concurrent-log-handler) from 0.9.17 to 0.9.19. - [Release notes](https://github.com/Preston-Landers/concurrent-log-handler/releases) - [Changelog](https://github.com/Preston-Landers/concurrent-log-handler/blob/master/CHANGELOG.md) - [Commits](https://github.com/Preston-Landers/concurrent-log-handler/compare/0.9.17...0.9.19) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump actions/upload-artifact from v2.2.0 to v2.2.1 (#528) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from v2.2.0 to v2.2.1. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v2.2.0...726a6dcd0199f578459862705eed35cda05af50b) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump keyring from 21.4.0 to 21.5.0 (#529) Bumps [keyring](https://github.com/jaraco/keyring) from 21.4.0 to 21.5.0. - [Release notes](https://github.com/jaraco/keyring/releases) - [Changelog](https://github.com/jaraco/keyring/blob/master/CHANGES.rst) - [Commits](https://github.com/jaraco/keyring/compare/v21.4.0...v21.5.0) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Try pyinstaller-4.1 (#533) * Try aiohttp 3.7.3 * fixed mac build * updated formating fixed eslint updated deps compiled locales * fixed locale file format * removed unused code * added "add plot directory" when plots are already there * slovak translation correction * use electron starter from dev branch * updated router and fixed electron build * used TXCH for testnet * removed eslintcache from the git * used correct translation (TXCH) for English locale * added missing plurals library * used same visualization for total size * removed unused code * update package-lock.json * start harvester and farmer * Bump blspy to 0.2.9 and brute force Python 3.9 timelord issue (#540) * Is a bad chiavdf cached? * Bump blspy * Check the env * rm unexpected vdf_client in python 3.9 * Remove debug echo * Bump pos/vdf/bip158/bls for python 3.9 wheels * downgrade to last good chiavdf - no 3.9 ubuntu yet * Bump pos/vdf/bip158/bls for python 3.9 wheels * downgrade to last good chiavdf - no 3.9 ubuntu yet Co-authored-by: Yostra <straya@chia.net> Co-authored-by: Gene Hoffman <30377676+hoffmang9@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Matthew Howard <matt@chia.net> Co-authored-by: Gene Hoffman <hoffmang@hoffmang.com> Co-authored-by: Bill Blanke <wjb2002@flex.com> Co-authored-by: wjblanke <wjb98672@gmail.com>
2020-11-25 22:48:20 +03:00
type=uint32(TransactionType.OUTGOING_TX.value),
name=spend_bundle.name(),
2020-03-19 22:11:58 +03:00
)
2020-04-21 16:55:59 +03:00
2020-04-28 04:42:08 +03:00
async def push_transaction(self, tx: TransactionRecord) -> None:
""" Use this API to send transactions. """
await self.wallet_state_manager.add_pending_transaction(tx)
2020-04-21 16:55:59 +03:00
# This is to be aggregated together with a coloured coin offer to ensure that the trade happens
2020-12-11 10:27:03 +03:00
async def create_spend_bundle_relative_chia(self, chia_amount: int, exclude: List[Coin]) -> SpendBundle:
2020-04-21 16:55:59 +03:00
list_of_solutions = []
utxos = None
# If we're losing value then get coins with at least that much value
# If we're gaining value then our amount doesn't matter
if chia_amount < 0:
utxos = await self.select_coins(abs(chia_amount), exclude)
2020-04-21 16:55:59 +03:00
else:
utxos = await self.select_coins(0, exclude)
2020-04-21 16:55:59 +03:00
2020-09-14 12:29:03 +03:00
assert len(utxos) > 0
2020-04-21 16:55:59 +03:00
# Calculate output amount given sum of utxos
spend_value = sum([coin.amount for coin in utxos])
chia_amount = spend_value + chia_amount
# Create coin solutions for each utxo
output_created = None
for coin in utxos:
puzzle = await self.puzzle_for_puzzle_hash(coin.puzzle_hash)
2020-04-21 16:55:59 +03:00
if output_created is None:
newpuzhash = await self.get_new_puzzlehash()
primaries = [{"puzzlehash": newpuzhash, "amount": chia_amount}]
solution = self.make_solution(primaries=primaries)
output_created = coin
2021-02-21 22:24:57 +03:00
list_of_solutions.append(CoinSolution(coin, puzzle, solution))
2020-04-21 16:55:59 +03:00
await self.hack_populate_secret_keys_for_coin_solutions(list_of_solutions)
spend_bundle = await sign_coin_solutions(
list_of_solutions,
self.secret_key_store.secret_key_for_public_key,
self.wallet_state_manager.constants.AGG_SIG_ME_ADDITIONAL_DATA,
self.wallet_state_manager.constants.MAX_BLOCK_COST_CLVM,
)
2020-09-17 01:53:22 +03:00
return spend_bundle