Merge branch 'integration' of github.com:Chia-Network/chia-blockchain into integration

This commit is contained in:
Mariano Sorgente 2020-03-02 15:17:20 +09:00
commit e372d362b4
No known key found for this signature in database
GPG Key ID: 0F866338C369278C
17 changed files with 375 additions and 109 deletions

View File

@ -5,8 +5,8 @@ class ConditionCost(Enum):
# Condition Costs
AGG_SIG = 20
CREATE_COIN = 200
ASSERT_COIN_CONSUMED = 5
ASSERT_MY_COIN_ID = 5
ASSERT_TIME_EXCEEDS = 5
ASSERT_BLOCK_INDEX_EXCEEDS = 5
ASSERT_BLOCK_AGE_EXCEEDS = 5
ASSERT_COIN_CONSUMED = 0
ASSERT_MY_COIN_ID = 0
ASSERT_TIME_EXCEEDS = 0
ASSERT_BLOCK_INDEX_EXCEEDS = 0
ASSERT_BLOCK_AGE_EXCEEDS = 0

View File

@ -827,20 +827,25 @@ class Blockchain:
fork_h = self._find_fork_for_lca(old_lca, self.lca_block)
# Rollback to fork
await self.unspent_store.rollback_lca_to_block(fork_h)
# Nuke DiffStore
self.unspent_store.nuke_diffs()
# Add blocks between fork point and new lca
fork_hash = self.height_to_hash[fork_h]
fork_head = self.headers[fork_hash]
await self._from_fork_to_lca(fork_head, self.lca_block)
# Create DiffStore
await self._create_diffs_for_tips(self.lca_block)
if not self.store.get_sync_mode():
await self.recreate_diff_stores()
else:
# If LCA has not changed just update the difference
self.unspent_store.nuke_diffs()
# Create DiffStore
await self._create_diffs_for_tips(self.lca_block)
async def recreate_diff_stores(self):
# Nuke DiffStore
self.unspent_store.nuke_diffs()
# Create DiffStore
await self._create_diffs_for_tips(self.lca_block)
def _reconsider_heights(self, old_lca: Optional[Header], new_lca: Header):
"""
Update the mapping from height to block hash, when the lca changes.

View File

@ -31,8 +31,6 @@ class CoinStore:
"""
coin_record_db: aiosqlite.Connection
# Whether or not we are syncing
sync_mode: bool = False
lock: asyncio.Lock
lca_coin_records: Dict[str, CoinRecord]
head_diffs: Dict[bytes32, DiffStore]

View File

@ -543,6 +543,8 @@ class FullNode:
potential_fut_blocks = (self.store.get_potential_future_blocks()).copy()
self.store.set_sync_mode(False)
await self.blockchain.recreate_diff_stores()
async with self.store.lock:
await self.store.clear_sync_info()
@ -596,8 +598,14 @@ class FullNode:
A peer notifies us of a new transaction.
Requests a full transaction if we haven't seen it previously, and if the fees are enough.
"""
# Ignore if syncing
if self.store.get_sync_mode():
breakpoint()
return
# Ignore if already seen
if self.mempool_manager.seen(transaction.transaction_id):
return
elif self.mempool_manager.is_fee_enough(transaction.fees, transaction.cost):
requestTX = full_node_protocol.RequestTransaction(
transaction.transaction_id
@ -613,6 +621,10 @@ class FullNode:
self, request: full_node_protocol.RequestTransaction
) -> OutboundMessageGenerator:
""" Peer has requested a full transaction from us. """
# Ignore if syncing
if self.store.get_sync_mode():
breakpoint()
return
spend_bundle = self.mempool_manager.get_spendbundle(request.transaction_id)
if spend_bundle is None:
reject = full_node_protocol.RejectTransactionRequest(request.transaction_id)
@ -640,6 +652,10 @@ class FullNode:
Receives a full transaction from peer.
If tx is added to mempool, send tx_id to others. (new_transaction)
"""
# Ignore if syncing
if self.store.get_sync_mode():
breakpoint()
return
async with self.unspent_store.lock:
cost, error = await self.mempool_manager.add_spendbundle(tx.transaction)
if cost is not None:
@ -1727,3 +1743,20 @@ class FullNode:
Message("response_reject_additions", request),
Delivery.BROADCAST,
)
@api_request
async def request_transaction_with_filter(
self, request: src.protocols.full_node_protocol.ReceivedMempoolFilter
):
mempool_filter = PyBIP158(request.filter)
transactions = await self.mempool_manager.get_items_not_in_filter(
mempool_filter
)
for tx in transactions:
transaction = full_node_protocol.RespondTransaction(tx.spend_bundle)
yield OutboundMessage(
NodeType.FULL_NODE,
Message("respond_transaction", transaction),
Delivery.RESPOND,
)

View File

@ -2,6 +2,8 @@ import collections
from typing import Dict, Optional, Tuple, List, Set
import logging
from chiabip158 import PyBIP158
from src.consensus.constants import constants as consensus_constants
from src.util.bundle_tools import best_solution_program
from src.types.full_block import FullBlock
@ -35,8 +37,8 @@ class MempoolManager:
# Transactions that were unable to enter mempool, used for retry. (they were invalid)
self.potential_txs: Dict[bytes32, SpendBundle] = {}
# TODO limit the size of seen_bundle_hashes
self.seen_bundle_hashes: Set[bytes32] = set()
# Keep track of seen spend_bundles
self.seen_bundle_hashes: Dict[bytes32, bytes32] = {}
# Mempool for each tip
self.mempools: Dict[bytes32, Mempool] = {}
@ -51,6 +53,7 @@ class MempoolManager:
# MEMPOOL_SIZE = 60000
self.mempool_size = tx_per_sec * sec_per_block * block_buffer_count
self.potential_cache_size = 300
self.seen_cache_size = 10000
self.coinbase_freeze = self.constants["COINBASE_FREEZE_PERIOD"]
# TODO This is hack, it should use proper cost, const. Minimize work, double check/verify solution.
@ -89,6 +92,11 @@ class MempoolManager:
return True
return False
def maybe_pop_seen(self):
while len(self.seen_bundle_hashes) > self.seen_cache_size:
first_in = list(self.seen_bundle_hashes.keys())[0]
self.seen_bundle_hashes.pop(first_in)
async def add_spendbundle(
self, new_spend: SpendBundle, to_pool: Mempool = None
) -> Tuple[Optional[uint64], Optional[Err]]:
@ -96,7 +104,8 @@ class MempoolManager:
Tries to add spendbundle to either self.mempools or to_pool if it's specified.
Returns true if it's added in any of pools, Returns error if it fails.
"""
self.seen_bundle_hashes.add(new_spend.name())
self.seen_bundle_hashes[new_spend.name()] = new_spend.name()
self.maybe_pop_seen()
# Calculate the cost and fees
program = best_solution_program(new_spend)
@ -282,7 +291,7 @@ class MempoolManager:
while len(self.potential_txs) > self.potential_cache_size:
first_in = list(self.potential_txs.keys())[0]
del self.potential_txs[first_in]
self.potential_txs.pop(first_in)
def seen(self, bundle_hash: bytes32) -> bool:
""" Return true if we saw this spendbundle before """
@ -336,6 +345,39 @@ class MempoolManager:
self.mempools = new_pools
async def create_filter_for_pools(self) -> bytes:
# Create filter for items in mempools
byte_array_tx: List[bytes32] = []
added_items: Set[bytes32] = set()
for mempool in self.mempools:
for key, item in mempool.spends.items():
if key in added_items:
continue
added_items.add(key)
byte_array_tx.append(bytearray(item.name()))
bip158: PyBIP158 = PyBIP158(byte_array_tx)
encoded_filter = bytes(bip158.GetEncoded())
return encoded_filter
async def get_items_not_in_filter(
self, mempool_filter: PyBIP158
) -> List[MempoolItem]:
items: List[MempoolItem] = []
added_items: Set[bytes32] = set()
for mempool in self.mempools:
for key, item in mempool.spends.items():
if key in added_items:
continue
if mempool_filter.Match(key):
continue
added_items.add(key)
items.append(item)
return items
async def update_pool(self, pool: Mempool, new_tip: FullBlock):
"""
Called when new tip extends the tip we had mempool for.

View File

@ -204,3 +204,8 @@ class RespondHeaderBlock:
class RejectHeaderBlockRequest:
height: uint32
header_hash: bytes32
@dataclass(frozen=True)
class ReceivedMempoolFilter:
filter: bytes

View File

@ -49,7 +49,7 @@ class RpcWalletApiHandler:
"""
Returns a new puzzlehash
"""
puzzlehash = self.wallet_node.wallet.get_new_puzzlehash().hex()
puzzlehash = (await self.wallet_node.wallet.get_new_puzzlehash()).hex()
response = {
"puzzlehash": puzzlehash,
}

View File

@ -15,11 +15,17 @@ puzzle_prog_template = load_clvm("make_puzzle_m_of_n_direct.clvm")
def puzzle_for_m_of_public_key_list(m, public_key_list):
format_tuple = tuple([
binutils.disassemble(Program.to(_))
for _ in (puzzle_prog_template, m, public_key_list)
])
puzzle_src = "((c (q %s) (c (q %s) (c (q %s) (a)))))" % (format_tuple[0], format_tuple[1], format_tuple[2])
format_tuple = tuple(
[
binutils.disassemble(Program.to(_))
for _ in (puzzle_prog_template, m, public_key_list)
]
)
puzzle_src = "((c (q %s) (c (q %s) (c (q %s) (a)))))" % (
format_tuple[0],
format_tuple[1],
format_tuple[2],
)
puzzle_prog = binutils.assemble(puzzle_src)
return Program.to(puzzle_prog)

View File

@ -0,0 +1,13 @@
from enum import Enum
class WalletType(Enum):
# Condition Costs
STANDARD_WALLET = 0
RATE_LIMITED = 1
ATOMIC_SWAP = 2
AUTHORIZED_PAYEE = 3
MULTI_SIG = 4
CUSTODY = 5
COLORED_COIN = 6
RECOVERABLE = 7

View File

@ -25,6 +25,7 @@ from src.wallet.puzzles.puzzle_utils import (
make_assert_coin_consumed_condition,
make_create_coin_condition,
)
from src.wallet.util.wallet_types import WalletType
from src.wallet.wallet_state_manager import WalletStateManager
@ -34,8 +35,6 @@ class Wallet:
key_config: Dict
config: Dict
server: Optional[ChiaServer]
next_address: int = 0
pubkey_num_lookup: Dict[bytes, int]
wallet_state_manager: WalletStateManager
log: logging.Logger
@ -64,17 +63,13 @@ class Wallet:
self.log = logging.getLogger(__name__)
self.wallet_state_manager = wallet_state_manager
self.pubkey_num_lookup = {}
self.server = None
return self
def get_next_public_key(self) -> PublicKey:
pubkey = self.private_key.public_child(self.next_address).get_public_key()
self.pubkey_num_lookup[pubkey.serialize()] = self.next_address
self.next_address = self.next_address + 1
self.wallet_state_manager.next_address = self.next_address
def get_public_key(self, index) -> PublicKey:
pubkey = self.private_key.public_child(index).get_public_key()
return pubkey
async def get_confirmed_balance(self) -> uint64:
@ -83,41 +78,28 @@ class Wallet:
async def get_unconfirmed_balance(self) -> uint64:
return await self.wallet_state_manager.get_unconfirmed_balance()
def can_generate_puzzle_hash(self, hash: bytes32) -> bool:
return any(
map(
lambda child: hash
== puzzle_for_pk(
self.private_key.public_child(child).get_public_key().serialize()
).get_hash(),
reversed(range(self.next_address)),
)
)
async def can_generate_puzzle_hash(self, hash: bytes32) -> bool:
return await self.wallet_state_manager.tx_store.puzzle_hash_exists(hash)
def puzzle_for_pk(self, pubkey) -> Program:
return puzzle_for_pk(pubkey)
def get_new_puzzle(self) -> Program:
pubkey: bytes = self.get_next_public_key().serialize()
puzzle: Program = puzzle_for_pk(pubkey)
return puzzle
def get_new_puzzlehash(self) -> bytes32:
puzzle: Program = self.get_new_puzzle()
async def get_new_puzzlehash(self) -> bytes32:
index = await self.wallet_state_manager.tx_store.get_max_derivation_path()
index += 1
pubkey: bytes = self.get_public_key(index).serialize()
puzzle: Program = self.puzzle_for_pk(pubkey)
puzzlehash: bytes32 = puzzle.get_hash()
self.wallet_state_manager.puzzlehash_set.add(puzzlehash)
await self.wallet_state_manager.tx_store.add_derivation_path_of_interest(
index, puzzlehash, pubkey, WalletType.STANDARD_WALLET
)
return puzzlehash
def set_server(self, server: ChiaServer):
self.server = server
def sign(self, value: bytes32, pubkey: PublicKey):
private_key = self.private_key.private_child(
self.pubkey_num_lookup[pubkey]
).get_private_key()
bls_key = BLSPrivateKey(private_key)
return bls_key.sign(value)
def make_solution(self, primaries=None, min_time=0, me=None, consumed=None):
ret = []
if primaries:
@ -134,12 +116,17 @@ class Wallet:
ret.append(make_assert_my_coin_id_condition(me["id"]))
return clvm.to_sexp_f([puzzle_for_conditions(ret), []])
def get_keys(self, hash: bytes32) -> Optional[Tuple[PublicKey, ExtendedPrivateKey]]:
for child in range(self.next_address):
pubkey = self.private_key.public_child(child).get_public_key()
if hash == puzzle_for_pk(pubkey.serialize()).get_hash():
return pubkey, self.private_key.private_child(child).get_private_key()
return None
async def get_keys(
self, hash: bytes32
) -> Optional[Tuple[PublicKey, ExtendedPrivateKey]]:
index_for_puzzlehash = await self.wallet_state_manager.tx_store.index_for_puzzle_hash(
hash
)
if index_for_puzzlehash == -1:
raise
pubkey = self.private_key.public_child(index_for_puzzlehash).get_public_key()
private = self.private_key.private_child(index_for_puzzlehash).get_private_key()
return pubkey, private
async def generate_unsigned_transaction(
self, amount: int, newpuzzlehash: bytes32, fee: int = 0
@ -153,7 +140,7 @@ class Wallet:
change = spend_value - amount - fee
for coin in utxos:
puzzle_hash = coin.puzzle_hash
maybe = self.get_keys(puzzle_hash)
maybe = await self.get_keys(puzzle_hash)
if not maybe:
return []
pubkey, secretkey = maybe
@ -161,7 +148,7 @@ class Wallet:
if output_created is False:
primaries = [{"puzzlehash": newpuzzlehash, "amount": amount}]
if change > 0:
changepuzzlehash = self.get_new_puzzlehash()
changepuzzlehash = await self.get_new_puzzlehash()
primaries.append({"puzzlehash": changepuzzlehash, "amount": change})
solution = self.make_solution(primaries=primaries)
@ -171,10 +158,10 @@ class Wallet:
spends.append((puzzle, CoinSolution(coin, solution)))
return spends
def sign_transaction(self, spends: List[Tuple[Program, CoinSolution]]):
async def sign_transaction(self, spends: List[Tuple[Program, CoinSolution]]):
sigs = []
for puzzle, solution in spends:
keys = self.get_keys(solution.coin.puzzle_hash)
keys = await self.get_keys(solution.coin.puzzle_hash)
if not keys:
return None
pubkey, secretkey = keys
@ -208,7 +195,7 @@ class Wallet:
)
if len(transaction) == 0:
return None
return self.sign_transaction(transaction)
return await self.sign_transaction(transaction)
async def push_transaction(self, spend_bundle: SpendBundle):
""" Use this API to send transactions. """
@ -219,7 +206,10 @@ class Wallet:
if self.server:
msg = OutboundMessage(
NodeType.FULL_NODE,
Message("respond_transaction", full_node_protocol.RespondTransaction(spend_bundle)),
Message(
"respond_transaction",
full_node_protocol.RespondTransaction(spend_bundle),
),
Delivery.BROADCAST,
)
async for reply in self.server.push_message(msg):

View File

@ -114,11 +114,15 @@ class WalletNode:
additions: List[Coin] = []
if self.wallet.can_generate_puzzle_hash(response.header.data.coinbase.puzzle_hash):
if await self.wallet.can_generate_puzzle_hash(
response.header.data.coinbase.puzzle_hash
):
await self.wallet_state_manager.coin_added(
response.header.data.coinbase, response.height, True
)
if self.wallet.can_generate_puzzle_hash(response.header.data.fees_coin.puzzle_hash):
if await self.wallet.can_generate_puzzle_hash(
response.header.data.fees_coin.puzzle_hash
):
await self.wallet_state_manager.coin_added(
response.header.data.fees_coin, response.height, True
)
@ -132,13 +136,13 @@ class WalletNode:
additions.extend(additions_for_npc(npc_list))
for added_coin in additions:
if self.wallet.can_generate_puzzle_hash(added_coin.puzzle_hash):
if await self.wallet.can_generate_puzzle_hash(added_coin.puzzle_hash):
await self.wallet_state_manager.coin_added(
added_coin, response.height, False
)
for npc in npc_list:
if self.wallet.can_generate_puzzle_hash(npc.puzzle_hash):
if await self.wallet.can_generate_puzzle_hash(npc.puzzle_hash):
await self.wallet_state_manager.coin_removed(
npc.coin_name, response.height
)

View File

@ -18,13 +18,11 @@ class WalletStateManager:
tx_store: WalletTransactionStore
header_hash: List[bytes32]
start_index: int
next_address: int
log: logging.Logger
# TODO Don't allow user to send tx until wallet is synced
synced: bool
puzzlehash_set: set
@staticmethod
async def create(
@ -46,9 +44,7 @@ class WalletStateManager:
self.wallet_store = wallet_store
self.tx_store = tx_store
self.synced = False
self.next_address = 0
self.puzzlehash_set = set()
return self
async def get_confirmed_balance(self) -> uint64:
@ -70,7 +66,7 @@ class WalletStateManager:
for record in unconfirmed_tx:
for coin in record.additions:
if coin.puzzle_hash in self.puzzlehash_set:
if await self.tx_store.puzzle_hash_exists(coin.puzzle_hash):
addition_amount += coin.amount
for coin in record.removals:
removal_amount += coin.amount

View File

@ -5,6 +5,7 @@ import aiosqlite
from src.types.sized_bytes import bytes32
from src.util.ints import uint32
from src.wallet.transaction_record import TransactionRecord
from src.wallet.util.wallet_types import WalletType
class WalletTransactionStore:
@ -60,6 +61,33 @@ class WalletTransactionStore:
"CREATE INDEX IF NOT EXISTS tx_created_time on transaction_record(created_at_time)"
)
await self.transaction_db.execute(
(
f"CREATE TABLE IF NOT EXISTS derivation_paths("
f"id int PRIMARY KEY,"
f" pubkey text,"
f" puzzle_hash text,"
f" wallet_type int,"
f" used int)"
)
)
await self.transaction_db.execute(
"CREATE INDEX IF NOT EXISTS ph on derivation_paths(puzzle_hash)"
)
await self.transaction_db.execute(
"CREATE INDEX IF NOT EXISTS pubkey on derivation_paths(pubkey)"
)
await self.transaction_db.execute(
"CREATE INDEX IF NOT EXISTS wallet_type on derivation_paths(wallet_type)"
)
await self.transaction_db.execute(
"CREATE INDEX IF NOT EXISTS used on derivation_paths(wallet_type)"
)
await self.transaction_db.commit()
# Lock
self.lock = asyncio.Lock() # external
@ -183,3 +211,62 @@ class WalletTransactionStore:
records.append(record)
return records
async def add_derivation_path_of_interest(
self, index: int, puzzlehash: bytes32, pubkey: bytes, wallet_type: WalletType
):
cursor = await self.transaction_db.execute(
"INSERT OR REPLACE INTO derivation_paths VALUES(?, ?, ?, ?, ?)",
(index, pubkey.hex(), puzzlehash.hex(), wallet_type.value, 0),
)
await cursor.close()
await self.transaction_db.commit()
async def puzzle_hash_exists(self, puzzle_hash: bytes32) -> bool:
cursor = await self.transaction_db.execute(
"SELECT * from derivation_paths WHERE puzzle_hash=?", (puzzle_hash.hex(),)
)
rows = await cursor.fetchall()
await cursor.close()
if len(list(rows)) > 0:
return True
return False
async def index_for_pubkey(self, pubkey: str) -> int:
cursor = await self.transaction_db.execute(
"SELECT * from derivation_paths WHERE pubkey=?", (pubkey,)
)
row = await cursor.fetchone()
await cursor.close()
if row:
return row[0]
return -1
async def index_for_puzzle_hash(self, pubkey: bytes32) -> int:
cursor = await self.transaction_db.execute(
"SELECT * from derivation_paths WHERE puzzle_hash=?", (pubkey.hex(),)
)
row = await cursor.fetchone()
await cursor.close()
if row:
return row[0]
return -1
async def get_max_derivation_path(self):
cursor = await self.transaction_db.execute(
"SELECT MAX(id) FROM derivation_paths;"
)
row = await cursor.fetchone()
await cursor.close()
if row[0]:
return row[0]
return 0

View File

@ -52,7 +52,9 @@ class TestFullSync:
return
await asyncio.sleep(0.1)
raise Exception("Took too long to process blocks")
raise Exception(
f"Took too long to process blocks, stopped at: {time.time() - start_unf}"
)
@pytest.mark.asyncio
async def test_short_sync(self, two_nodes):

View File

@ -7,6 +7,7 @@ from src.server.outbound_message import OutboundMessage
from src.protocols import full_node_protocol
from src.types.condition_var_pair import ConditionVarPair
from src.types.condition_opcodes import ConditionOpcode
from src.types.hashable.spend_bundle import SpendBundle
from src.util.ints import uint64
from tests.setup_nodes import setup_two_nodes, test_constants, bt
from tests.wallet_tools import WalletTool
@ -31,7 +32,7 @@ class TestMempool:
@pytest.mark.asyncio
async def test_basic_mempool(self, two_nodes):
num_blocks = 3
num_blocks = 2
wallet_a = WalletTool()
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
wallet_receiver = WalletTool()
@ -51,7 +52,7 @@ class TestMempool:
spend_bundle = wallet_a.generate_signed_transaction(
1000, receiver_puzzlehash, block.header.data.coinbase
)
assert spend_bundle is not None
tx: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(
spend_bundle
)
@ -65,7 +66,7 @@ class TestMempool:
@pytest.mark.asyncio
async def test_coinbase_freeze(self, two_nodes_standard_freeze):
num_blocks = 3
num_blocks = 2
wallet_a = WalletTool()
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
wallet_receiver = WalletTool()
@ -117,7 +118,7 @@ class TestMempool:
@pytest.mark.asyncio
async def test_double_spend(self, two_nodes):
num_blocks = 3
num_blocks = 2
wallet_a = WalletTool()
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
wallet_receiver = WalletTool()
@ -166,7 +167,7 @@ class TestMempool:
@pytest.mark.asyncio
async def test_double_spend_with_higher_fee(self, two_nodes):
num_blocks = 3
num_blocks = 2
wallet_a = WalletTool()
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
wallet_receiver = WalletTool()
@ -214,7 +215,7 @@ class TestMempool:
@pytest.mark.asyncio
async def test_invalid_block_index(self, two_nodes):
num_blocks = 3
num_blocks = 2
wallet_a = WalletTool()
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
wallet_receiver = WalletTool()
@ -257,7 +258,7 @@ class TestMempool:
@pytest.mark.asyncio
async def test_correct_block_index(self, two_nodes):
num_blocks = 3
num_blocks = 2
wallet_a = WalletTool()
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
wallet_receiver = WalletTool()
@ -300,7 +301,7 @@ class TestMempool:
@pytest.mark.asyncio
async def test_invalid_block_age(self, two_nodes):
num_blocks = 3
num_blocks = 2
wallet_a = WalletTool()
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
wallet_receiver = WalletTool()
@ -384,7 +385,7 @@ class TestMempool:
@pytest.mark.asyncio
async def test_correct_my_id(self, two_nodes):
num_blocks = 4
num_blocks = 2
wallet_a = WalletTool()
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
wallet_receiver = WalletTool()
@ -427,7 +428,7 @@ class TestMempool:
@pytest.mark.asyncio
async def test_invalid_my_id(self, two_nodes):
num_blocks = 4
num_blocks = 2
wallet_a = WalletTool()
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
wallet_receiver = WalletTool()
@ -457,7 +458,6 @@ class TestMempool:
1000, receiver_puzzlehash, block.header.data.coinbase, dic
)
assert spend_bundle1 is not None
tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(
spend_bundle1
)
@ -472,7 +472,7 @@ class TestMempool:
@pytest.mark.asyncio
async def test_assert_time_exceeds(self, two_nodes):
num_blocks = 4
num_blocks = 2
wallet_a = WalletTool()
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
wallet_receiver = WalletTool()
@ -502,7 +502,6 @@ class TestMempool:
1000, receiver_puzzlehash, block.header.data.coinbase, dic
)
assert spend_bundle1 is not None
tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(
spend_bundle1
)
@ -517,7 +516,7 @@ class TestMempool:
@pytest.mark.asyncio
async def test_assert_time_exceeds_both_cases(self, two_nodes):
num_blocks = 4
num_blocks = 2
wallet_a = WalletTool()
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
wallet_receiver = WalletTool()
@ -558,9 +557,6 @@ class TestMempool:
outbound: OutboundMessage = _
assert outbound.message.function != "new_transaction"
sb1 = full_node_1.mempool_manager.get_spendbundle(spend_bundle1.name())
assert sb1 is None
# Sleep so that 3 sec passes
await asyncio.sleep(3)
@ -575,3 +571,101 @@ class TestMempool:
sb1 = full_node_1.mempool_manager.get_spendbundle(spend_bundle1.name())
assert sb1 is spend_bundle1
@pytest.mark.asyncio
async def test_correct_coin_consumed(self, two_nodes):
num_blocks = 2
wallet_a = WalletTool()
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
wallet_receiver = WalletTool()
receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
blocks = bt.get_consecutive_blocks(
test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash
)
full_node_1, full_node_2, server_1, server_2 = two_nodes
block = blocks[1]
block2 = blocks[2]
for b in blocks:
async for _ in full_node_1.respond_block(
full_node_protocol.RespondBlock(b)
):
pass
cvp = ConditionVarPair(
ConditionOpcode.ASSERT_COIN_CONSUMED,
block2.header.data.coinbase.name(),
None,
)
dic = {cvp.opcode: [cvp]}
spend_bundle1 = wallet_a.generate_signed_transaction(
1000, receiver_puzzlehash, block.header.data.coinbase, dic
)
spend_bundle2 = wallet_a.generate_signed_transaction(
1000, receiver_puzzlehash, block2.header.data.coinbase
)
bundle = SpendBundle.aggregate([spend_bundle1, spend_bundle2])
tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(
bundle
)
async for _ in full_node_1.respond_transaction(tx1):
outbound: OutboundMessage = _
# Maybe transaction means that it's accepted in mempool
assert outbound.message.function == "new_transaction"
mempool_bundle = full_node_1.mempool_manager.get_spendbundle(bundle.name())
assert mempool_bundle is bundle
@pytest.mark.asyncio
async def test_invalid_coin_consumed(self, two_nodes):
num_blocks = 2
wallet_a = WalletTool()
coinbase_puzzlehash = wallet_a.get_new_puzzlehash()
wallet_receiver = WalletTool()
receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
blocks = bt.get_consecutive_blocks(
test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash
)
full_node_1, full_node_2, server_1, server_2 = two_nodes
block = blocks[1]
block2 = blocks[2]
for b in blocks:
async for _ in full_node_1.respond_block(
full_node_protocol.RespondBlock(b)
):
pass
cvp = ConditionVarPair(
ConditionOpcode.ASSERT_COIN_CONSUMED,
block2.header.data.coinbase.name(),
None,
)
dic = {cvp.opcode: [cvp]}
spend_bundle1 = wallet_a.generate_signed_transaction(
1000, receiver_puzzlehash, block.header.data.coinbase, dic
)
tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(
spend_bundle1
)
async for _ in full_node_1.respond_transaction(tx1):
outbound: OutboundMessage = _
# Maybe transaction means that it's accepted in mempool
assert outbound.message.function == "new_transaction"
mempool_bundle = full_node_1.mempool_manager.get_spendbundle(
spend_bundle1.name()
)
assert mempool_bundle is None

View File

@ -30,12 +30,9 @@ class TestFilter:
await wallet_node.wallet_store._clear_database()
num_blocks = 2
ph = await wallet.get_new_puzzlehash()
blocks = bt.get_consecutive_blocks(
test_constants,
num_blocks,
[],
10,
reward_puzzlehash=wallet.get_new_puzzlehash(),
test_constants, num_blocks, [], 10, reward_puzzlehash=ph,
)
for i in range(1, num_blocks):

View File

@ -31,12 +31,9 @@ class TestWallet:
await wallet_node.tx_store._clear_database()
num_blocks = 10
ph = await wallet.get_new_puzzlehash()
blocks = bt.get_consecutive_blocks(
test_constants,
num_blocks,
[],
10,
reward_puzzlehash=wallet.get_new_puzzlehash(),
test_constants, num_blocks, [], 10, reward_puzzlehash=ph,
)
for i in range(1, num_blocks):
@ -68,12 +65,9 @@ class TestWallet:
await wallet_node_b.tx_store._clear_database()
num_blocks = 10
ph = await wallet.get_new_puzzlehash()
blocks = bt.get_consecutive_blocks(
test_constants,
num_blocks,
[],
10,
reward_puzzlehash=wallet.get_new_puzzlehash(),
test_constants, num_blocks, [], 10, reward_puzzlehash=ph,
)
for i in range(1, num_blocks):
@ -85,7 +79,7 @@ class TestWallet:
assert await wallet.get_confirmed_balance() == 144000000000000
spend_bundle = await wallet.generate_signed_transaction(
10, wallet_b.get_new_puzzlehash(), 0
10, await wallet_b.get_new_puzzlehash(), 0
)
await wallet.push_transaction(spend_bundle)