This commit is contained in:
Yostra 2020-08-10 17:09:45 -07:00 committed by Gene Hoffman
parent 357a63e5e4
commit 9667e1c783
8 changed files with 123 additions and 92 deletions

View File

@ -322,8 +322,12 @@ async def show_async(args, parser):
print("Wallet summary cannot be displayed")
else:
print("Balances")
for wallet_id, summary in summaries_response["wallet_summaries"].items():
balances_response = await wallet_client.get_wallet_balance(wallet_id)
for wallet_id, summary in summaries_response[
"wallet_summaries"
].items():
balances_response = await wallet_client.get_wallet_balance(
wallet_id
)
if "balances" not in balances_response:
print("Balances cannot be displayed")
continue

View File

@ -7,7 +7,6 @@ from typing import List, Optional, Tuple, Dict, Callable
from blspy import PrivateKey
from src.types.coin import Coin
from src.util.byte_types import hexstr_to_bytes
from src.util.chech32 import encode_puzzle_hash, decode_puzzle_hash
from src.util.keychain import (
@ -87,7 +86,7 @@ class WalletRpcApi:
origin["parent_coin_info"],
origin["puzzle_hash"],
origin["amount"],
request["admin_pubkey"]
request["admin_pubkey"],
)
return {"success": success}
except Exception as e:
@ -202,14 +201,14 @@ class WalletRpcApi:
data = {
"status": "FAILED",
"reason": f"Failed to generate signed transaction. Error: {e}",
"id": wallet_id
"id": wallet_id,
}
return data
if tx is None:
data = {
"status": "FAILED",
"reason": "Failed to generate signed transaction",
"id": wallet_id
"id": wallet_id,
}
return data
try:
@ -218,7 +217,7 @@ class WalletRpcApi:
data = {
"status": "FAILED",
"reason": f"Failed to push transaction {e}",
"id": wallet_id
"id": wallet_id,
}
return data
sent = False
@ -361,30 +360,38 @@ class WalletRpcApi:
if request["rl_type"] == "admin":
log.info("Create rl admin wallet")
try:
rl_admin: RLWallet = await RLWallet.create_rl_admin(wallet_state_manager)
rl_admin: RLWallet = await RLWallet.create_rl_admin(
wallet_state_manager
)
success = await rl_admin.admin_create_coin(
uint64(int(request["interval"])),
uint64(int(request["limit"])),
request["pubkey"],
uint64(int(request["amount"]))
uint64(int(request["amount"])),
)
return {"success": success,
"id": rl_admin.wallet_info.id,
"type": rl_admin.wallet_info.type,
"origin": rl_admin.rl_info.rl_origin,
"pubkey": rl_admin.rl_info.admin_pubkey.hex()}
return {
"success": success,
"id": rl_admin.wallet_info.id,
"type": rl_admin.wallet_info.type,
"origin": rl_admin.rl_info.rl_origin,
"pubkey": rl_admin.rl_info.admin_pubkey.hex(),
}
except Exception as e:
log.error("FAILED {e}")
return {"success": False, "reason": str(e)}
elif request["rl_type"] == "user":
log.info("Create rl user wallet")
try:
rl_user: RLWallet = await RLWallet.create_rl_user(wallet_state_manager)
rl_user: RLWallet = await RLWallet.create_rl_user(
wallet_state_manager
)
return {"success": True,
"id": rl_user.wallet_info.id,
"type": rl_user.wallet_info.type,
"pubkey": rl_user.rl_info.user_pubkey.hex()}
return {
"success": True,
"id": rl_user.wallet_info.id,
"type": rl_user.wallet_info.type,
"pubkey": rl_user.rl_info.user_pubkey.hex(),
}
except Exception as e:
log.error("FAILED {e}")
return {"success": False, "reason": str(e)}
@ -432,18 +439,14 @@ class WalletRpcApi:
request["amount"], puzzle_hash
)
except Exception as e:
data = {
"status": "FAILED",
"reason": f"{e}",
"id": wallet_id
}
data = {"status": "FAILED", "reason": f"{e}", "id": wallet_id}
return data
if tx is None:
data = {
"status": "FAILED",
"reason": "Failed to generate signed transaction",
"id": wallet_id
"id": wallet_id,
}
return data
try:
@ -469,8 +472,7 @@ class WalletRpcApi:
continue
status, err = sent_to[0][1], sent_to[0][2]
if status == MempoolInclusionStatus.SUCCESS:
data = {"status": "SUCCESS",
"id": wallet_id}
data = {"status": "SUCCESS", "id": wallet_id}
sent = True
break
elif status == MempoolInclusionStatus.PENDING:
@ -487,7 +489,7 @@ class WalletRpcApi:
data = {
"status": "FAILED",
"reason": "Timed out. Transaction may or may not have been sent.",
"id": wallet_id
"id": wallet_id,
}
return data
@ -814,4 +816,4 @@ class WalletRpcApi:
"reason": "Timed out. Transaction may or may not have been sent.",
}
return data
return data

View File

@ -91,7 +91,7 @@ class RLWallet(AbstractWallet):
unused,
token_bytes(),
pubkey_bytes,
WalletType.RATE_LIMITED.value,
WalletType.RATE_LIMITED,
wallet_info.id,
)
]
@ -270,8 +270,12 @@ class RLWallet(AbstractWallet):
True,
)
rl_puzzle_hash = rl_puzzle.get_tree_hash()
if await self.wallet_state_manager.puzzle_store.puzzle_hash_exists(rl_puzzle_hash):
raise Exception("Cannot create multiple Rate Limited wallets under the same keys. This will change in a future release.")
if await self.wallet_state_manager.puzzle_store.puzzle_hash_exists(
rl_puzzle_hash
):
raise Exception(
"Cannot create multiple Rate Limited wallets under the same keys. This will change in a future release."
)
index = await self.wallet_state_manager.puzzle_store.index_for_pubkey(
G1Element.from_bytes(self.rl_info.user_pubkey)
)
@ -537,6 +541,8 @@ class RLWallet(AbstractWallet):
raise Exception("One ore more of the elements of rl_info is None")
spends = []
coin = clawback_coin
if self.rl_info.rl_origin is None:
raise ValueError("Origin not initialized")
puzzle = rl_puzzle_for_pk(
self.rl_info.user_pubkey,
self.rl_info.limit,
@ -579,7 +585,9 @@ class RLWallet(AbstractWallet):
)
if transaction is None:
return None
return await self.sign_clawback_transaction(transaction, self.rl_info.admin_pubkey)
return await self.sign_clawback_transaction(
transaction, self.rl_info.admin_pubkey
)
async def clawback_rl_coin_transaction(self):
to_puzzle_hash = self.get_new_puzzlehash()
@ -694,4 +702,4 @@ class RLWallet(AbstractWallet):
async def push_transaction(self, tx: TransactionRecord) -> None:
""" Use this API to send transactions. """
await self.wallet_state_manager.add_pending_transaction(tx)
await self.wallet_state_manager.add_pending_transaction(tx)

View File

@ -39,15 +39,15 @@ def rl_puzzle_for_pk(
opcode_myid = ConditionOpcode.ASSERT_MY_COIN_ID.hex()
TEMPLATE_MY_PARENT_ID = "(sha256 (f (r (r (r (r (r (r (a)))))))) (f (r (a))) (f (r (r (r (r (r (r (r (a))))))))))"
TEMPLATE_SINGLETON_RL = f"((c (i (i (= {TEMPLATE_MY_PARENT_ID} (f (a))) (q 1) (= (f (a)) (q 0x{origin_id}))) (q ()) (q (x (q \"Parent doesnt satisfy RL conditions\")))) (a)))" # noqa: E501
TEMPLATE_BLOCK_AGE = f"((c (i (i (= (* (f (r (r (r (r (r (a))))))) (q {rate_amount})) (* (f (r (r (r (r (a)))))) (q {interval_time}))) (q 1) (q (> (* (f (r (r (r (r (r (a))))))) (q {rate_amount})) (* (f (r (r (r (r (a))))))) (q {interval_time})))) (q (c (q 0x{opcode_coin_block_age}) (c (f (r (r (r (r (r (a))))))) (q ())))) (q (x (q \"wrong min block time\")))) (a) ))" # noqa: E501
TEMPLATE_SINGLETON_RL = f'((c (i (i (= {TEMPLATE_MY_PARENT_ID} (f (a))) (q 1) (= (f (a)) (q 0x{origin_id}))) (q ()) (q (x (q "Parent doesnt satisfy RL conditions")))) (a)))' # noqa: E501
TEMPLATE_BLOCK_AGE = f'((c (i (i (= (* (f (r (r (r (r (r (a))))))) (q {rate_amount})) (* (f (r (r (r (r (a)))))) (q {interval_time}))) (q 1) (q (> (* (f (r (r (r (r (r (a))))))) (q {rate_amount})) (* (f (r (r (r (r (a))))))) (q {interval_time})))) (q (c (q 0x{opcode_coin_block_age}) (c (f (r (r (r (r (r (a))))))) (q ())))) (q (x (q "wrong min block time")))) (a) ))' # noqa: E501
TEMPLATE_MY_ID = f"(c (q 0x{opcode_myid}) (c (sha256 (f (a)) (f (r (a))) (f (r (r (a))))) (q ())))" # noqa: E501
CREATE_CHANGE = f"(c (q 0x{opcode_create}) (c (f (r (a))) (c (- (f (r (r (a)))) (f (r (r (r (r (a))))))) (q ()))))" # noqa: E501
CREATE_NEW_COIN = f"(c (q 0x{opcode_create}) (c (f (r (r (r (a))))) (c (f (r (r (r (r (a)))))) (q ()))))" # noqa: E501
RATE_LIMIT_PUZZLE = f"(c {TEMPLATE_SINGLETON_RL} (c {TEMPLATE_BLOCK_AGE} (c {CREATE_CHANGE} (c {TEMPLATE_MY_ID} (c {CREATE_NEW_COIN} (q ()))))))" # noqa: E501
TEMPLATE_MY_PARENT_ID_2 = "(sha256 (f (r (r (r (r (r (r (r (r (a)))))))))) (f (r (a))) (f (r (r (r (r (r (r (r (a))))))))))" # noqa: E501
TEMPLATE_SINGLETON_RL_2 = f"((c (i (i (= {TEMPLATE_MY_PARENT_ID_2} (f (r (r (r (r (r (a)))))))) (q 1) (= (f (r (r (r (r (r (a))))))) (q 0x{origin_id}))) (q (c (q 1) (q ()))) (q (x (q \"Parent doesnt satisfy RL conditions\")))) (a)))" # noqa: E501
TEMPLATE_SINGLETON_RL_2 = f'((c (i (i (= {TEMPLATE_MY_PARENT_ID_2} (f (r (r (r (r (r (a)))))))) (q 1) (= (f (r (r (r (r (r (a))))))) (q 0x{origin_id}))) (q (c (q 1) (q ()))) (q (x (q "Parent doesnt satisfy RL conditions")))) (a)))' # noqa: E501
CREATE_CONSOLIDATED = f"(c (q 0x{opcode_create}) (c (f (r (a))) (c (+ (f (r (r (r (r (a)))))) (f (r (r (r (r (r (r (a))))))))) (q ()))))" # noqa: E501
MODE_TWO_ME_STRING = f"(c (q 0x{opcode_myid}) (c (sha256 (f (r (r (r (r (r (a))))))) (f (r (a))) (f (r (r (r (r (r (r (a))))))))) (q ())))" # noqa: E501
CREATE_LOCK = f"(c (q 0x{opcode_create}) (c (sha256tree (c (q 7) (c (c (q 5) (c (c (q 1) (c (sha256 (f (r (r (a)))) (f (r (r (r (a))))) (f (r (r (r (r (a))))))) (q ()))) (c (q (q ())) (q ())))) (q ())))) (c (q 0) (q ()))))" # noqa: E501

View File

@ -210,13 +210,16 @@ class WalletPuzzleStore:
return None
async def index_for_puzzle_hash_and_wallet(self, puzzle_hash: bytes32, wallet_id: uint32) -> Optional[uint32]:
async def index_for_puzzle_hash_and_wallet(
self, puzzle_hash: bytes32, wallet_id: uint32
) -> Optional[uint32]:
"""
Returns the derivation path for the puzzle_hash.
Returns None if not present.
"""
cursor = await self.db_connection.execute(
"SELECT * from derivation_paths WHERE puzzle_hash=? and wallet_id=?;", (puzzle_hash.hex(), wallet_id,)
"SELECT * from derivation_paths WHERE puzzle_hash=? and wallet_id=?;",
(puzzle_hash.hex(), wallet_id,),
)
row = await cursor.fetchone()
await cursor.close()

View File

@ -281,13 +281,15 @@ class WalletStateManager:
break
type = target_wallet.rl_info.type
if type == "user":
pubkey = G1Element.from_bytes(target_wallet.rl_info.user_pubkey)
rl_pubkey = G1Element.from_bytes(target_wallet.rl_info.user_pubkey)
else:
pubkey = G1Element.from_bytes(target_wallet.rl_info.admin_pubkey)
puzzle: Program = target_wallet.puzzle_for_pk(pubkey)
puzzle_hash: bytes32 = puzzle.get_tree_hash()
rl_pubkey = G1Element.from_bytes(
target_wallet.rl_info.admin_pubkey
)
rl_puzzle: Program = target_wallet.puzzle_for_pk(rl_pubkey)
puzzle_hash: bytes32 = rl_puzzle.get_tree_hash()
rl_index = self.get_derivation_index(pubkey)
rl_index = self.get_derivation_index(rl_pubkey)
if rl_index == -1:
break
@ -295,7 +297,7 @@ class WalletStateManager:
DerivationRecord(
uint32(rl_index),
puzzle_hash,
pubkey,
rl_pubkey,
target_wallet.wallet_info.type,
uint32(target_wallet.wallet_info.id),
)
@ -1398,7 +1400,9 @@ class WalletStateManager:
meta_data_bytes = json.dumps(meta_data).encode()
signature = bytes(
AugSchemeMPL.sign(backup_pk, std_hash(encrypted) + std_hash(meta_data_bytes))
AugSchemeMPL.sign(
backup_pk, std_hash(encrypted) + std_hash(meta_data_bytes)
)
).hex()
backup["data"] = encrypted.decode()

View File

@ -19,7 +19,7 @@ class TestCCWallet:
@pytest.fixture(scope="function")
async def three_wallet_nodes(self):
async for _ in setup_simulators_and_wallets(
1, 3, {"COINBASE_FREEZE_PERIOD": 0}
1, 3, {"COINBASE_FREEZE_PERIOD": 0}
):
yield _
@ -45,67 +45,80 @@ class TestCCWallet:
await full_node_1.farm_new_block(FarmNewBlockProtocol(ph))
api_user = WalletRpcApi(wallet_node_1)
val = await api_user.create_new_wallet({'wallet_type': 'rl_wallet',
'rl_type': 'user'})
val = await api_user.create_new_wallet(
{"wallet_type": "rl_wallet", "rl_type": "user"}
)
assert isinstance(val, dict)
assert val['success']
assert val['id']
assert val['type'] == 'RATE_LIMITED'
user_wallet_id = val['id']
pubkey = val['pubkey']
assert val["success"]
assert val["id"]
assert val["type"] == "RATE_LIMITED"
pubkey = val["pubkey"]
api_admin = WalletRpcApi(wallet_node)
val = await api_admin.create_new_wallet({'wallet_type': 'rl_wallet',
'rl_type': 'admin',
'interval': 2,
'limit': 1,
'pubkey': pubkey,
'amount': 100})
val = await api_admin.create_new_wallet(
{
"wallet_type": "rl_wallet",
"rl_type": "admin",
"interval": 2,
"limit": 1,
"pubkey": pubkey,
"amount": 100,
}
)
assert isinstance(val, dict)
assert val['success']
assert val['id']
assert val['type'] == 'RATE_LIMITED'
assert val['origin']
assert val['pubkey']
admin_wallet_id = val['id']
admin_pubkey = val['pubkey']
origin: Coin = val['origin']
assert val["success"]
assert val["id"]
assert val["type"] == "RATE_LIMITED"
assert val["origin"]
assert val["pubkey"]
admin_pubkey = val["pubkey"]
origin: Coin = val["origin"]
val = await api_user.rl_set_user_info({'wallet_id': 2,
'interval': 2,
'limit': 1,
'origin': {"parent_coin_info": origin.parent_coin_info.hex(),
"puzzle_hash": origin.puzzle_hash.hex(),
"amount": origin.amount},
'admin_pubkey': admin_pubkey})
assert val['success']
val = await api_user.rl_set_user_info(
{
"wallet_id": 2,
"interval": 2,
"limit": 1,
"origin": {
"parent_coin_info": origin.parent_coin_info.hex(),
"puzzle_hash": origin.puzzle_hash.hex(),
"amount": origin.amount,
},
"admin_pubkey": admin_pubkey,
}
)
assert val["success"]
assert (await api_user.get_wallet_balance({'wallet_id': 2}))['confirmed_wallet_balance'] == 0
for i in range(0, 2*num_blocks):
assert (await api_user.get_wallet_balance({"wallet_id": 2}))[
"confirmed_wallet_balance"
] == 0
for i in range(0, 2 * num_blocks):
await full_node_1.farm_new_block(FarmNewBlockProtocol(32 * b"\0"))
async def check_balance(api, wallet_id):
balance_response = await api.get_wallet_balance({'wallet_id': wallet_id})
balance_response = await api.get_wallet_balance({"wallet_id": wallet_id})
balance = balance_response["confirmed_wallet_balance"]
return balance
await time_out_assert(15, check_balance, 100, api_user, 2)
assert (await api_user.get_wallet_balance({'wallet_id': 2}))['confirmed_wallet_balance'] == 100
assert (await api_user.get_wallet_balance({"wallet_id": 2}))[
"confirmed_wallet_balance"
] == 100
receiving_wallet = wallet_node_2.wallet_state_manager.main_wallet
puzzle_hash = await receiving_wallet.get_new_puzzlehash()
assert await receiving_wallet.get_spendable_balance() == 0
val = await api_user.send_transaction({'wallet_id': 2,
'amount': 3,
'fee': 0,
'puzzle_hash': puzzle_hash.hex()})
val = await api_user.send_transaction(
{"wallet_id": 2, "amount": 3, "fee": 0, "puzzle_hash": puzzle_hash.hex()}
)
assert val['status'] == 'SUCCESS'
for i in range(0, 2*num_blocks):
assert val["status"] == "SUCCESS"
for i in range(0, 2 * num_blocks):
await full_node_1.farm_new_block(FarmNewBlockProtocol(32 * b"\0"))
await time_out_assert(15, check_balance, 97, api_user, 2)
await time_out_assert(15, receiving_wallet.get_spendable_balance, 3)
assert (await api_user.get_wallet_balance({'wallet_id': 2}))['confirmed_wallet_balance'] == 97
assert (await api_user.get_wallet_balance({"wallet_id": 2}))[
"confirmed_wallet_balance"
] == 97

View File

@ -1,13 +1,11 @@
import asyncio
import time
import pytest
from src.simulator.simulator_protocol import FarmNewBlockProtocol
from src.types.peer_info import PeerInfo
from src.util.ints import uint16, uint64, uint32
from src.util.ints import uint16, uint64
from src.wallet.rl_wallet.rl_wallet import RLWallet
from src.wallet.transaction_record import TransactionRecord
from tests.setup_nodes import setup_simulators_and_wallets
from tests.time_out_assert import time_out_assert
@ -81,7 +79,6 @@ class TestCCWallet:
balance = await rl_user.rl_available_balance()
tx_record = await rl_user.rl_generate_signed_transaction(1, 32 * b"\0")
now = uint64(int(time.time()))
await wallet_node_1.wallet_state_manager.main_wallet.push_transaction(tx_record)