Ejemplo n.º 1
0
def run_test(puzzle_hash, solution, payments):
    run = asyncio.get_event_loop().run_until_complete

    remote = make_client_server()

    coin = farm_spendable_coin(remote, puzzle_hash)
    spend_bundle = build_spend_bundle(coin, solution)

    # push it
    r = run(remote.push_tx(tx=spend_bundle))
    assert r["response"].startswith("accepted")
    print(r)

    # confirm it
    farm_spendable_coin(remote)

    # get unspents
    r = run(remote.all_unspents())
    print("unspents = %s" % r.get("unspents"))
    unspents = r["unspents"]

    # ensure all outputs are there
    for puzzle_hash, amount in payments:
        expected_coin = Coin(coin.name(), puzzle_hash, amount)
        name = expected_coin.name()
        assert name in unspents
        unspent = run(remote.unspent_for_coin_name(coin_name=name))
        assert unspent.confirmed_block_index == 2
        assert unspent.spent_block_index == 0
Ejemplo n.º 2
0
async def process_blocks(wallet, ledger_api, last_known_header,
                         current_header_hash):
    r = await ledger_api.hash_preimage(hash=current_header_hash)
    header = Header.from_bytes(r)
    body = Body.from_bytes(await
                           ledger_api.hash_preimage(hash=header.body_hash))
    if header.previous_hash != last_known_header:
        await process_blocks(wallet, ledger_api, last_known_header,
                             header.previous_hash)
    print(f'processing block {HeaderHash(header)}')
    additions = list(additions_for_body(body))
    removals = removals_for_body(body)
    removals = [
        Coin.from_bytes(await ledger_api.hash_preimage(hash=x))
        for x in removals
    ]
    wallet.notify(additions, removals)
    clawback_coins = [coin for coin in additions if wallet.is_in_escrow(coin)]
    if len(clawback_coins) != 0:
        print(f'WARNING! Coins from this wallet have been moved to escrow!\n'
              f'Attempting to send a clawback for these coins:')
        for coin in clawback_coins:
            print(f'Coin ID: {coin.name()}, Amount: {coin.amount}')
        transaction = wallet.generate_clawback_transaction(clawback_coins)
        r = await ledger_api.push_tx(tx=transaction)
        if type(r) is RemoteError:
            print('Clawback failed')
        else:
            print('Clawback transaction submitted')
Ejemplo n.º 3
0
def commit_and_notify(remote, wallets, reward_recipient):
    run = asyncio.get_event_loop().run_until_complete
    coinbase_puzzle_hash = reward_recipient.get_new_puzzlehash()
    fees_puzzle_hash = reward_recipient.get_new_puzzlehash()
    r = run(
        remote.next_block(coinbase_puzzle_hash=coinbase_puzzle_hash,
                          fees_puzzle_hash=fees_puzzle_hash))
    body = r.get("body")

    additions = list(additions_for_body(body))
    removals = removals_for_body(body)
    removals = [
        Coin.from_bytes(run(remote.hash_preimage(hash=x))) for x in removals
    ]
    tip = run(remote.get_tip())
    index = int(tip["tip_index"])

    for wallet in wallets:
        if isinstance(wallet, RLWallet):
            spend_bundle = wallet.notify(additions, removals, index)
        else:
            spend_bundle = wallet.notify(additions, removals)
        if spend_bundle is not None:
            for bun in spend_bundle:
                _ = run(remote.push_tx(tx=bun))
Ejemplo n.º 4
0
    def generate_unsigned_transaction(self, amount, newpuzzlehash):
        if self.temp_balance < amount:
            return None  # TODO: Should we throw a proper error here, or just return None?
        utxos = self.select_coins(amount)
        spends = []
        output_id = None
        spend_value = sum([coin.amount for coin in utxos])
        change = spend_value - amount
        for coin in utxos:
            puzzle_hash = coin.puzzle_hash

            pubkey, secretkey = self.get_keys(puzzle_hash)
            puzzle = self.puzzle_for_pk(pubkey.serialize())
            if output_id is None:
                primaries = [{'puzzlehash': newpuzzlehash, 'amount': amount}]
                if change > 0:
                    changepuzzlehash = self.get_new_puzzlehash()
                    primaries.append({
                        'puzzlehash': changepuzzlehash,
                        'amount': change
                    })
                    # add change coin into temp_utxo set
                    self.temp_utxos.add(Coin(coin, changepuzzlehash, change))
                solution = make_solution(primaries=primaries)
                output_id = sha256(coin.name() + newpuzzlehash)
            else:
                solution = make_solution(consumed=[coin.name()])
            spends.append((puzzle, CoinSolution(coin, solution)))
        self.temp_balance -= amount
        return spends
Ejemplo n.º 5
0
def farm_new_block(previous_header: HeaderHash, previous_signature: Signature,
                   block_index: int, proof_of_space: ProofOfSpace,
                   spend_bundle: SpendBundle, coinbase_coin: Coin,
                   coinbase_signature: BLSSignature,
                   fees_puzzle_hash: ProgramHash, timestamp: uint64):
    """
    Steps:
        - collect up a consistent set of removals and solutions
        - run solutions to get the additions
        - select a timestamp = max(now, minimum_legal_timestamp)
        - create blank extension data
        - collect up coinbase coin with coinbase signature (if solo mining, we get these locally)
        - return Header, Body
    """

    program_cost = 0

    assert validate_spend_bundle_signature(spend_bundle)
    solution_program = best_solution_program(spend_bundle)
    extension_data = std_hash(b'')

    block_index_hash = block_index.to_bytes(32, "big")
    fees_coin = Coin(block_index_hash, fees_puzzle_hash, spend_bundle.fees())
    body = Body(coinbase_signature, coinbase_coin, fees_coin, solution_program,
                program_cost, spend_bundle.aggregated_signature)

    header = Header(previous_header, previous_signature, timestamp,
                    proof_of_space, body, extension_data)
    return header, body
Ejemplo n.º 6
0
async def do_spend_coin(wallet, storage, input):
    """
    UI to spend a coin.
    """
    coins = []
    while True:
        coin_str = input("Enter hex id of coin to spend> ")
        if len(coin_str) == 0:
            break
        coin_name = bytes.fromhex(coin_str)
        preimage = await storage.hash_preimage(hash=coin_name)
        if preimage is None:
            print(f"can't find coin id {coin_name.hex()}")
            continue
        coin = Coin.from_bytes(preimage)
        coin_puzzle_hash_hex = coin.puzzle_hash.hex()
        print(f"coin puzzle hash is {coin_puzzle_hash_hex}")
        coins.append(coin)
    if len(coins) == 0:
        return
    dest_address = "14c56fdefb47e2208de54b6c609a907c522348c96e8cfb41c7a8c75f44835dd9"
    print(f"sending 1 coin to {dest_address}, rest fees")

    # create an unfinalized SpendBundle
    pst = spend_coin(wallet, coins, dest_address)
    pst_encoded = bytes(pst)
    print(pst_encoded.hex())

    # keep requesting signatures until finalized
    sigs = []
    while True:
        sig_str = input("Enter a signature> ")
        try:
            sig = BLSSignature.from_bytes(bytes.fromhex(sig_str))
        except Exception as ex:
            print("failed: %s" % ex)
            continue
        sigs.append(sig)
        sigs = list(set(sigs))
        spend_bundle, summary_list = finalize_pst(wallet, pst, sigs)
        if spend_bundle:
            break
        for summary in summary_list:
            print(
                "coin %s has %d of %d sigs"
                % (summary[0].name(), len(summary[2]), summary[3])
            )
    print("spend bundle = %s" % bytes(spend_bundle).hex())

    # optionally send to ledger sim
    r = input(f"Send to ledger sim? (y/n)> ")
    if r.lower().startswith("y"):
        r = await storage.ledger_sim().push_tx(tx=spend_bundle)
    return spend_bundle
Ejemplo n.º 7
0
async def update_ledger(wallet, ledger_api, most_recent_header):
    if most_recent_header is None:
        r = await ledger_api.get_all_blocks()
    else:
        r = await ledger_api.get_recent_blocks(most_recent_header=most_recent_header)
    update_list = BodyList.from_bytes(r)
    for body in update_list:
        additions = list(additions_for_body(body))
        print(additions)
        removals = removals_for_body(body)
        removals = [Coin.from_bytes(await ledger_api.hash_preimage(hash=x)) for x in removals]
        wallet.notify(additions, removals)
Ejemplo n.º 8
0
async def new_block(wallet, ledger_api):
    coinbase_puzzle_hash = wallet.get_new_puzzlehash()
    fees_puzzle_hash = wallet.get_new_puzzlehash()
    r = await ledger_api.next_block(coinbase_puzzle_hash=coinbase_puzzle_hash, fees_puzzle_hash=fees_puzzle_hash)
    body = r["body"]
    # breakpoint()
    most_recent_header = r['header']
    # breakpoint()
    additions = list(additions_for_body(body))
    removals = removals_for_body(body)
    removals = [Coin.from_bytes(await ledger_api.hash_preimage(hash=x)) for x in removals]
    wallet.notify(additions, removals)
    return most_recent_header
Ejemplo n.º 9
0
async def all_coins_and_unspents(storage):
    """
    Query the ledger sim instance for all coins and unspents.
    """
    coins = []
    unspents = []
    coin_name_unspent_pairs = [_ async for _ in storage.all_unspents()]
    for coin_name, unspent in coin_name_unspent_pairs:
        preimage = await storage.hash_preimage(hash=coin_name)
        coin = Coin.from_bytes(preimage)
        unspents.append(unspent)
        coins.append(coin)
    return coins, unspents
Ejemplo n.º 10
0
async def restore(ledger_api, wallet, header_hash):
    recovery_string = input(
        'Enter the recovery string of the wallet to be restored: ')
    recovery_dict = recovery_string_to_dict(recovery_string)
    root_public_key_serialized = recovery_dict['root_public_key'].serialize()

    recovery_pubkey = recovery_dict['root_public_key'].public_child(
        0).get_public_key().serialize()
    unspent_coins = await get_unspent_coins(ledger_api, header_hash)
    recoverable_coins = []
    print('scanning', end='')
    for coin in unspent_coins:
        if wallet.can_generate_puzzle_hash_with_root_public_key(
                coin.puzzle_hash, root_public_key_serialized,
                recovery_dict['stake_factor'],
                recovery_dict['escrow_duration']):
            recoverable_coins.append(coin)
            print('*', end='', flush=True)
        else:
            print('.', end='', flush=True)
    recoverable_amount = sum([coin.amount for coin in recoverable_coins])
    print(
        f'\nFound {len(recoverable_coins)} coins totaling {recoverable_amount}'
    )
    stake_amount = round(recoverable_amount *
                         (recovery_dict['stake_factor'] - 1))
    if wallet.current_balance < stake_amount:
        print(
            f'Insufficient funds to stake the recovery process. {stake_amount} needed.'
        )
        return
    for coin in recoverable_coins:
        print(f'Coin ID: {coin.name()}, Amount: {coin.amount}')
        pubkey = wallet.find_pubkey_for_hash(coin.puzzle_hash,
                                             root_public_key_serialized,
                                             recovery_dict['stake_factor'],
                                             recovery_dict['escrow_duration'])
        signed_transaction, destination_puzzlehash, amount = \
            wallet.generate_signed_recovery_to_escrow_transaction(coin,
                                                                  recovery_pubkey,
                                                                  pubkey,
                                                                  recovery_dict['stake_factor'],
                                                                  recovery_dict['escrow_duration'])
        child = Coin(coin.name(), destination_puzzlehash, amount)
        r = await ledger_api.push_tx(tx=signed_transaction)
        if type(r) is RemoteError:
            print(f'Failed to recover {coin.name()}')
        else:
            print(f'Recovery transaction submitted for Coin ID: {coin.name()}')
            wallet.escrow_coins[recovery_string].add(child)
Ejemplo n.º 11
0
def commit_and_notify(remote, wallets, reward_recipient):
    run = asyncio.get_event_loop().run_until_complete
    coinbase_puzzle_hash = reward_recipient.get_new_puzzlehash()
    fees_puzzle_hash = reward_recipient.get_new_puzzlehash()
    r = run(remote.next_block(coinbase_puzzle_hash=coinbase_puzzle_hash,
                              fees_puzzle_hash=fees_puzzle_hash))
    body = r.get("body")

    additions = list(additions_for_body(body))
    removals = [Coin.from_bytes(run(remote.hash_preimage(hash=x))) for x in removals_for_body(body)]

    for wallet in wallets:
        wallet.notify(additions, removals)

    return additions, removals
Ejemplo n.º 12
0
async def process_blocks(wallet, ledger_api, last_known_header,
                         current_header_hash):
    r = await ledger_api.hash_preimage(hash=current_header_hash)
    header = Header.from_bytes(r)
    body = Body.from_bytes(await
                           ledger_api.hash_preimage(hash=header.body_hash))
    if header.previous_hash != last_known_header:
        await process_blocks(wallet, ledger_api, last_known_header,
                             header.previous_hash)
    print(f'processing block {HeaderHash(header)}')
    additions = list(additions_for_body(body))
    removals = removals_for_body(body)
    removals = [
        Coin.from_bytes(await ledger_api.hash_preimage(hash=x))
        for x in removals
    ]
    wallet.notify(additions, removals)
Ejemplo n.º 13
0
async def update_ledger(wallet, ledger_api, most_recent_header):
    if most_recent_header is None:
        r = await ledger_api.get_all_blocks()
    else:
        r = await ledger_api.get_recent_blocks(most_recent_header=most_recent_header)
    update_list = BodyList.from_bytes(r)
    tip = await ledger_api.get_tip()
    index = int(tip["tip_index"])
    for body in update_list:
        additions = list(additions_for_body(body))
        removals = removals_for_body(body)
        removals = [Coin.from_bytes(await ledger_api.hash_preimage(hash=x)) for x in removals]
        spend_bundle_list = wallet.notify(additions, removals, index)
        if spend_bundle_list is not None:
            for spend_bundle in spend_bundle_list:
                _ = await ledger_api.push_tx(tx=spend_bundle)

    return most_recent_header
Ejemplo n.º 14
0
async def get_unspent_coins(ledger_api, header_hash):
    r = await ledger_api.get_tip()
    if r['genesis_hash'] == header_hash:
        return set()

    r = await ledger_api.hash_preimage(hash=header_hash)
    header = Header.from_bytes(r)
    unspent_coins = await get_unspent_coins(ledger_api, header.previous_hash)
    body = Body.from_bytes(await
                           ledger_api.hash_preimage(hash=header.body_hash))
    additions = list(additions_for_body(body))
    unspent_coins.update(additions)
    removals = removals_for_body(body)
    removals = [
        Coin.from_bytes(await ledger_api.hash_preimage(hash=x))
        for x in removals
    ]
    unspent_coins.difference_update(removals)
    return unspent_coins
Ejemplo n.º 15
0
def test_recovery_with_block_time():
    remote = make_client_server()
    run = asyncio.get_event_loop().run_until_complete
    wallet_a = RecoverableWallet(Decimal('1.1'), 1, DurationType.BLOCKS)
    wallet_b = RecoverableWallet(Decimal('1.1'), 1, DurationType.BLOCKS)
    farmer = RecoverableWallet(Decimal('1.1'), 1, DurationType.BLOCKS)
    wallets = [wallet_a, wallet_b, farmer]
    commit_and_notify(remote, wallets, wallet_a)
    commit_and_notify(remote, wallets, wallet_b)

    assert wallet_a.current_balance == 1000000000
    assert wallet_b.current_balance == 1000000000

    recovery_string = wallet_a.get_backup_string()
    recovery_dict = recovery_string_to_dict(recovery_string)
    root_public_key_serialized = bytes(recovery_dict['root_public_key'])
    recovery_pubkey = bytes(recovery_dict['root_public_key'].public_child(0))

    for coin in wallet_a.my_utxos.copy():
        pubkey = wallet_b.find_pubkey_for_hash(coin.puzzle_hash,
                                               root_public_key_serialized,
                                               recovery_dict['stake_factor'],
                                               recovery_dict['escrow_duration'],
                                               recovery_dict['duration_type'])
        signed_transaction, destination_puzzlehash, amount = \
            wallet_b.generate_signed_recovery_to_escrow_transaction(coin,
                                                                    recovery_pubkey,
                                                                    pubkey,
                                                                    recovery_dict['stake_factor'],
                                                                    recovery_dict['escrow_duration'],
                                                                    recovery_dict['duration_type'])
        child = Coin(coin.name(), destination_puzzlehash, amount)
        r = run(remote.push_tx(tx=signed_transaction))
        assert(type(r) is not RemoteError)
        wallet_b.escrow_coins[recovery_string].add(child)
        commit_and_notify(remote, wallets, farmer)
    assert wallet_a.current_balance == 0
    assert wallet_b.current_balance == 900000000

    # check too soon recovery transaction
    for recovery_string, coin_set in wallet_b.escrow_coins.items():
        recovery_dict = recovery_string_to_dict(recovery_string)
        root_public_key = recovery_dict['root_public_key']
        secret_key = recovery_dict['secret_key']
        escrow_duration = recovery_dict['escrow_duration']
        duration_type = recovery_dict['duration_type']

        signed_transaction = wallet_b.generate_recovery_transaction(coin_set,
                                                                    root_public_key,
                                                                    secret_key,
                                                                    escrow_duration,
                                                                    duration_type)
        r = run(remote.push_tx(tx=signed_transaction))
        assert type(r) is RemoteError

    # pass time
    commit_and_notify(remote, wallets, farmer)

    for recovery_string, coin_set in wallet_b.escrow_coins.items():
        recovery_dict = recovery_string_to_dict(recovery_string)
        root_public_key = recovery_dict['root_public_key']
        secret_key = recovery_dict['secret_key']
        escrow_duration = recovery_dict['escrow_duration']
        duration_type = recovery_dict['duration_type']

        signed_transaction = wallet_b.generate_recovery_transaction(coin_set,
                                                                    root_public_key,
                                                                    secret_key,
                                                                    escrow_duration,
                                                                    duration_type)
        r = run(remote.push_tx(tx=signed_transaction))
        assert type(r) is not RemoteError
    commit_and_notify(remote, wallets, farmer)
    assert wallet_a.current_balance == 0
    assert wallet_b.current_balance == 2000000000
Ejemplo n.º 16
0
def create_coinbase_coin(block_index: int, puzzle_hash: ProgramHash,
                         reward: uint64):
    block_index_as_hash = block_index.to_bytes(32, "big")
    return Coin(block_index_as_hash, puzzle_hash, reward)
Ejemplo n.º 17
0
def signature_for_coinbase(coin: Coin, pool_private_key: blspy.PrivateKey):
    message_hash = coin.name()
    return BLSSignature(
        pool_private_key.sign_prepend_prehashed(message_hash).serialize())