forked from LBRYCommunity/lbry-sdk
add tests for takeovers from amount changes in updates before/on/after activation
This commit is contained in:
parent
f77f2f6e80
commit
6155cda66f
4 changed files with 346 additions and 60 deletions
|
@ -1,20 +1,15 @@
|
||||||
import time
|
import time
|
||||||
import asyncio
|
import asyncio
|
||||||
import typing
|
import typing
|
||||||
import struct
|
|
||||||
from bisect import bisect_right
|
from bisect import bisect_right
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
from concurrent.futures.thread import ThreadPoolExecutor
|
|
||||||
from typing import Optional, List, Tuple, Set, DefaultDict, Dict, NamedTuple
|
from typing import Optional, List, Tuple, Set, DefaultDict, Dict, NamedTuple
|
||||||
from prometheus_client import Gauge, Histogram
|
from prometheus_client import Gauge, Histogram
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import array
|
|
||||||
import lbry
|
import lbry
|
||||||
from lbry.schema.claim import Claim
|
from lbry.schema.claim import Claim
|
||||||
from lbry.schema.mime_types import guess_stream_type
|
|
||||||
from lbry.wallet.ledger import Ledger, TestNetLedger, RegTestLedger
|
from lbry.wallet.ledger import Ledger, TestNetLedger, RegTestLedger
|
||||||
from lbry.wallet.constants import TXO_TYPES
|
|
||||||
from lbry.wallet.server.db.common import STREAM_TYPES, CLAIM_TYPES
|
|
||||||
|
|
||||||
from lbry.wallet.transaction import OutputScript, Output, Transaction
|
from lbry.wallet.transaction import OutputScript, Output, Transaction
|
||||||
from lbry.wallet.server.tx import Tx, TxOutput, TxInput
|
from lbry.wallet.server.tx import Tx, TxOutput, TxInput
|
||||||
|
@ -222,6 +217,7 @@ class BlockProcessor:
|
||||||
# attributes used for calculating stake activations and takeovers per block
|
# attributes used for calculating stake activations and takeovers per block
|
||||||
#################################
|
#################################
|
||||||
|
|
||||||
|
self.taken_over_names: Set[str] = set()
|
||||||
# txo to pending claim
|
# txo to pending claim
|
||||||
self.txo_to_claim: Dict[Tuple[int, int], StagedClaimtrieItem] = {}
|
self.txo_to_claim: Dict[Tuple[int, int], StagedClaimtrieItem] = {}
|
||||||
# claim hash to pending claim txo
|
# claim hash to pending claim txo
|
||||||
|
@ -234,6 +230,7 @@ class BlockProcessor:
|
||||||
self.removed_support_txos_by_name_by_claim: DefaultDict[str, DefaultDict[bytes, List[Tuple[int, int]]]] = \
|
self.removed_support_txos_by_name_by_claim: DefaultDict[str, DefaultDict[bytes, List[Tuple[int, int]]]] = \
|
||||||
defaultdict(lambda: defaultdict(list))
|
defaultdict(lambda: defaultdict(list))
|
||||||
self.abandoned_claims: Dict[bytes, StagedClaimtrieItem] = {}
|
self.abandoned_claims: Dict[bytes, StagedClaimtrieItem] = {}
|
||||||
|
self.updated_claims: Set[bytes] = set()
|
||||||
# removed activated support amounts by claim hash
|
# removed activated support amounts by claim hash
|
||||||
self.removed_active_support_amount_by_claim: DefaultDict[bytes, List[int]] = defaultdict(list)
|
self.removed_active_support_amount_by_claim: DefaultDict[bytes, List[int]] = defaultdict(list)
|
||||||
# pending activated support amounts by claim hash
|
# pending activated support amounts by claim hash
|
||||||
|
@ -513,6 +510,7 @@ class BlockProcessor:
|
||||||
).get_remove_activate_ops()
|
).get_remove_activate_ops()
|
||||||
)
|
)
|
||||||
previous_amount = previous_claim.amount
|
previous_amount = previous_claim.amount
|
||||||
|
self.updated_claims.add(claim_hash)
|
||||||
|
|
||||||
self.db.claim_to_txo[claim_hash] = ClaimToTXOValue(
|
self.db.claim_to_txo[claim_hash] = ClaimToTXOValue(
|
||||||
tx_num, nout, root_tx_num, root_idx, txo.amount, channel_signature_is_valid, claim_name
|
tx_num, nout, root_tx_num, root_idx, txo.amount, channel_signature_is_valid, claim_name
|
||||||
|
@ -730,6 +728,8 @@ class BlockProcessor:
|
||||||
|
|
||||||
def _get_pending_claim_amount(self, name: str, claim_hash: bytes, height=None) -> int:
|
def _get_pending_claim_amount(self, name: str, claim_hash: bytes, height=None) -> int:
|
||||||
if (name, claim_hash) in self.activated_claim_amount_by_name_and_hash:
|
if (name, claim_hash) in self.activated_claim_amount_by_name_and_hash:
|
||||||
|
if claim_hash in self.claim_hash_to_txo:
|
||||||
|
return self.txo_to_claim[self.claim_hash_to_txo[claim_hash]].amount
|
||||||
return self.activated_claim_amount_by_name_and_hash[(name, claim_hash)]
|
return self.activated_claim_amount_by_name_and_hash[(name, claim_hash)]
|
||||||
if (name, claim_hash) in self.possible_future_claim_amount_by_name_and_hash:
|
if (name, claim_hash) in self.possible_future_claim_amount_by_name_and_hash:
|
||||||
return self.possible_future_claim_amount_by_name_and_hash[(name, claim_hash)]
|
return self.possible_future_claim_amount_by_name_and_hash[(name, claim_hash)]
|
||||||
|
@ -771,7 +771,7 @@ class BlockProcessor:
|
||||||
_controlling = controlling_claims[_name]
|
_controlling = controlling_claims[_name]
|
||||||
return _controlling
|
return _controlling
|
||||||
|
|
||||||
names_with_abandoned_controlling_claims: List[str] = []
|
names_with_abandoned_or_updated_controlling_claims: List[str] = []
|
||||||
|
|
||||||
# get the claims and supports previously scheduled to be activated at this block
|
# get the claims and supports previously scheduled to be activated at this block
|
||||||
activated_at_height = self.db.get_activated_at_height(height)
|
activated_at_height = self.db.get_activated_at_height(height)
|
||||||
|
@ -784,7 +784,7 @@ class BlockProcessor:
|
||||||
nothing_is_controlling = not controlling
|
nothing_is_controlling = not controlling
|
||||||
staged_is_controlling = False if not controlling else claim_hash == controlling.claim_hash
|
staged_is_controlling = False if not controlling else claim_hash == controlling.claim_hash
|
||||||
controlling_is_abandoned = False if not controlling else \
|
controlling_is_abandoned = False if not controlling else \
|
||||||
controlling.claim_hash in names_with_abandoned_controlling_claims
|
controlling.claim_hash in names_with_abandoned_or_updated_controlling_claims
|
||||||
|
|
||||||
if nothing_is_controlling or staged_is_controlling or controlling_is_abandoned:
|
if nothing_is_controlling or staged_is_controlling or controlling_is_abandoned:
|
||||||
delay = 0
|
delay = 0
|
||||||
|
@ -822,7 +822,7 @@ class BlockProcessor:
|
||||||
for claim_hash, staged in self.abandoned_claims.items():
|
for claim_hash, staged in self.abandoned_claims.items():
|
||||||
controlling = get_controlling(staged.normalized_name)
|
controlling = get_controlling(staged.normalized_name)
|
||||||
if controlling and controlling.claim_hash == claim_hash:
|
if controlling and controlling.claim_hash == claim_hash:
|
||||||
names_with_abandoned_controlling_claims.append(staged.normalized_name)
|
names_with_abandoned_or_updated_controlling_claims.append(staged.normalized_name)
|
||||||
# print(f"\t{staged.name} needs takeover")
|
# print(f"\t{staged.name} needs takeover")
|
||||||
activation = self.db.get_activation(staged.tx_num, staged.position)
|
activation = self.db.get_activation(staged.tx_num, staged.position)
|
||||||
if activation > 0: # db returns -1 for non-existent txos
|
if activation > 0: # db returns -1 for non-existent txos
|
||||||
|
@ -845,13 +845,31 @@ class BlockProcessor:
|
||||||
continue
|
continue
|
||||||
controlling = get_controlling(name)
|
controlling = get_controlling(name)
|
||||||
if controlling and controlling.claim_hash == claim_hash and \
|
if controlling and controlling.claim_hash == claim_hash and \
|
||||||
name not in names_with_abandoned_controlling_claims:
|
name not in names_with_abandoned_or_updated_controlling_claims:
|
||||||
abandoned_support_check_need_takeover[(name, claim_hash)].extend(amounts)
|
abandoned_support_check_need_takeover[(name, claim_hash)].extend(amounts)
|
||||||
|
|
||||||
|
# get the controlling claims with updates to the claim to check if takeover is needed
|
||||||
|
for claim_hash in self.updated_claims:
|
||||||
|
if claim_hash in self.abandoned_claims:
|
||||||
|
continue
|
||||||
|
name = self._get_pending_claim_name(claim_hash)
|
||||||
|
if name is None:
|
||||||
|
continue
|
||||||
|
controlling = get_controlling(name)
|
||||||
|
if controlling and controlling.claim_hash == claim_hash and \
|
||||||
|
name not in names_with_abandoned_or_updated_controlling_claims:
|
||||||
|
names_with_abandoned_or_updated_controlling_claims.append(name)
|
||||||
|
|
||||||
# prepare to activate or delay activation of the pending claims being added this block
|
# prepare to activate or delay activation of the pending claims being added this block
|
||||||
for (tx_num, nout), staged in self.txo_to_claim.items():
|
for (tx_num, nout), staged in self.txo_to_claim.items():
|
||||||
|
is_delayed = not staged.is_update
|
||||||
|
if staged.claim_hash in self.db.claim_to_txo:
|
||||||
|
prev_txo = self.db.claim_to_txo[staged.claim_hash]
|
||||||
|
prev_activation = self.db.get_activation(prev_txo.tx_num, prev_txo.position)
|
||||||
|
if height < prev_activation or prev_activation < 0:
|
||||||
|
is_delayed = True
|
||||||
self.db_op_stack.extend_ops(get_delayed_activate_ops(
|
self.db_op_stack.extend_ops(get_delayed_activate_ops(
|
||||||
staged.normalized_name, staged.claim_hash, not staged.is_update, tx_num, nout, staged.amount,
|
staged.normalized_name, staged.claim_hash, is_delayed, tx_num, nout, staged.amount,
|
||||||
is_support=False
|
is_support=False
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@ -919,7 +937,7 @@ class BlockProcessor:
|
||||||
# go through claims where the controlling claim or supports to the controlling claim have been abandoned
|
# go through claims where the controlling claim or supports to the controlling claim have been abandoned
|
||||||
# check if takeovers are needed or if the name node is now empty
|
# check if takeovers are needed or if the name node is now empty
|
||||||
need_reactivate_if_takes_over = {}
|
need_reactivate_if_takes_over = {}
|
||||||
for need_takeover in names_with_abandoned_controlling_claims:
|
for need_takeover in names_with_abandoned_or_updated_controlling_claims:
|
||||||
existing = self.db.get_claim_txos_for_name(need_takeover)
|
existing = self.db.get_claim_txos_for_name(need_takeover)
|
||||||
has_candidate = False
|
has_candidate = False
|
||||||
# add existing claims to the queue for the takeover
|
# add existing claims to the queue for the takeover
|
||||||
|
@ -995,7 +1013,7 @@ class BlockProcessor:
|
||||||
amounts[controlling.claim_hash] = self._get_pending_effective_amount(name, controlling.claim_hash)
|
amounts[controlling.claim_hash] = self._get_pending_effective_amount(name, controlling.claim_hash)
|
||||||
winning_claim_hash = max(amounts, key=lambda x: amounts[x])
|
winning_claim_hash = max(amounts, key=lambda x: amounts[x])
|
||||||
if not controlling or (winning_claim_hash != controlling.claim_hash and
|
if not controlling or (winning_claim_hash != controlling.claim_hash and
|
||||||
name in names_with_abandoned_controlling_claims) or \
|
name in names_with_abandoned_or_updated_controlling_claims) or \
|
||||||
((winning_claim_hash != controlling.claim_hash) and (amounts[winning_claim_hash] > amounts[controlling.claim_hash])):
|
((winning_claim_hash != controlling.claim_hash) and (amounts[winning_claim_hash] > amounts[controlling.claim_hash])):
|
||||||
amounts_with_future_activations = {claim_hash: amount for claim_hash, amount in amounts.items()}
|
amounts_with_future_activations = {claim_hash: amount for claim_hash, amount in amounts.items()}
|
||||||
amounts_with_future_activations.update(
|
amounts_with_future_activations.update(
|
||||||
|
@ -1056,13 +1074,13 @@ class BlockProcessor:
|
||||||
k.position, height, name, amount
|
k.position, height, name, amount
|
||||||
).get_activate_ops()
|
).get_activate_ops()
|
||||||
)
|
)
|
||||||
|
self.taken_over_names.add(name)
|
||||||
self.db_op_stack.extend_ops(get_takeover_name_ops(name, winning_including_future_activations, height, controlling))
|
self.db_op_stack.extend_ops(get_takeover_name_ops(name, winning_including_future_activations, height, controlling))
|
||||||
self.touched_claim_hashes.add(winning_including_future_activations)
|
self.touched_claim_hashes.add(winning_including_future_activations)
|
||||||
if controlling and controlling.claim_hash not in self.abandoned_claims:
|
if controlling and controlling.claim_hash not in self.abandoned_claims:
|
||||||
self.touched_claim_hashes.add(controlling.claim_hash)
|
self.touched_claim_hashes.add(controlling.claim_hash)
|
||||||
elif not controlling or (winning_claim_hash != controlling.claim_hash and
|
elif not controlling or (winning_claim_hash != controlling.claim_hash and
|
||||||
name in names_with_abandoned_controlling_claims) or \
|
name in names_with_abandoned_or_updated_controlling_claims) or \
|
||||||
((winning_claim_hash != controlling.claim_hash) and (amounts[winning_claim_hash] > amounts[controlling.claim_hash])):
|
((winning_claim_hash != controlling.claim_hash) and (amounts[winning_claim_hash] > amounts[controlling.claim_hash])):
|
||||||
# print(f"\ttakeover by {winning_claim_hash.hex()} at {height}")
|
# print(f"\ttakeover by {winning_claim_hash.hex()} at {height}")
|
||||||
if (name, winning_claim_hash) in need_reactivate_if_takes_over:
|
if (name, winning_claim_hash) in need_reactivate_if_takes_over:
|
||||||
|
@ -1090,6 +1108,7 @@ class BlockProcessor:
|
||||||
position, height, name, amount
|
position, height, name, amount
|
||||||
).get_activate_ops()
|
).get_activate_ops()
|
||||||
)
|
)
|
||||||
|
self.taken_over_names.add(name)
|
||||||
self.db_op_stack.extend_ops(get_takeover_name_ops(name, winning_claim_hash, height, controlling))
|
self.db_op_stack.extend_ops(get_takeover_name_ops(name, winning_claim_hash, height, controlling))
|
||||||
if controlling and controlling.claim_hash not in self.abandoned_claims:
|
if controlling and controlling.claim_hash not in self.abandoned_claims:
|
||||||
self.touched_claim_hashes.add(controlling.claim_hash)
|
self.touched_claim_hashes.add(controlling.claim_hash)
|
||||||
|
@ -1114,7 +1133,9 @@ class BlockProcessor:
|
||||||
if controlling and controlling.claim_hash not in self.abandoned_claims:
|
if controlling and controlling.claim_hash not in self.abandoned_claims:
|
||||||
amounts[controlling.claim_hash] = self._get_pending_effective_amount(name, controlling.claim_hash)
|
amounts[controlling.claim_hash] = self._get_pending_effective_amount(name, controlling.claim_hash)
|
||||||
winning = max(amounts, key=lambda x: amounts[x])
|
winning = max(amounts, key=lambda x: amounts[x])
|
||||||
|
|
||||||
if (controlling and winning != controlling.claim_hash) or (not controlling and winning):
|
if (controlling and winning != controlling.claim_hash) or (not controlling and winning):
|
||||||
|
self.taken_over_names.add(name)
|
||||||
# print(f"\ttakeover from abandoned support {controlling.claim_hash.hex()} -> {winning.hex()}")
|
# print(f"\ttakeover from abandoned support {controlling.claim_hash.hex()} -> {winning.hex()}")
|
||||||
self.db_op_stack.extend_ops(get_takeover_name_ops(name, winning, height, controlling))
|
self.db_op_stack.extend_ops(get_takeover_name_ops(name, winning, height, controlling))
|
||||||
if controlling:
|
if controlling:
|
||||||
|
@ -1126,6 +1147,13 @@ class BlockProcessor:
|
||||||
self.activation_info_to_send_es[claim_id].append(TrendingNotification(height, added, prev_amount, new_amount))
|
self.activation_info_to_send_es[claim_id].append(TrendingNotification(height, added, prev_amount, new_amount))
|
||||||
|
|
||||||
def _get_cumulative_update_ops(self, height: int):
|
def _get_cumulative_update_ops(self, height: int):
|
||||||
|
# update the last takeover height for names with takeovers
|
||||||
|
for name in self.taken_over_names:
|
||||||
|
self.touched_claim_hashes.update(
|
||||||
|
{claim_hash for claim_hash in self.db.get_claims_for_name(name)
|
||||||
|
if claim_hash not in self.abandoned_claims}
|
||||||
|
)
|
||||||
|
|
||||||
# gather cumulative removed/touched sets to update the search index
|
# gather cumulative removed/touched sets to update the search index
|
||||||
self.removed_claim_hashes.update(set(self.abandoned_claims.keys()))
|
self.removed_claim_hashes.update(set(self.abandoned_claims.keys()))
|
||||||
self.touched_claim_hashes.difference_update(self.removed_claim_hashes)
|
self.touched_claim_hashes.difference_update(self.removed_claim_hashes)
|
||||||
|
@ -1359,6 +1387,8 @@ class BlockProcessor:
|
||||||
self.touched_claim_hashes.clear()
|
self.touched_claim_hashes.clear()
|
||||||
self.pending_reposted.clear()
|
self.pending_reposted.clear()
|
||||||
self.pending_channel_counts.clear()
|
self.pending_channel_counts.clear()
|
||||||
|
self.updated_claims.clear()
|
||||||
|
self.taken_over_names.clear()
|
||||||
|
|
||||||
async def backup_block(self):
|
async def backup_block(self):
|
||||||
# self.db.assert_flushed(self.flush_data())
|
# self.db.assert_flushed(self.flush_data())
|
||||||
|
|
|
@ -95,6 +95,7 @@ class SearchIndex:
|
||||||
if index_version != self.VERSION:
|
if index_version != self.VERSION:
|
||||||
self.logger.error("es search index has an incompatible version: %s vs %s", index_version, self.VERSION)
|
self.logger.error("es search index has an incompatible version: %s vs %s", index_version, self.VERSION)
|
||||||
raise IndexVersionMismatch(index_version, self.VERSION)
|
raise IndexVersionMismatch(index_version, self.VERSION)
|
||||||
|
await self.sync_client.indices.refresh(self.index)
|
||||||
return acked
|
return acked
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
|
|
|
@ -1299,10 +1299,10 @@ class HashXHistoryPrefixRow(PrefixRow):
|
||||||
return a.tobytes()
|
return a.tobytes()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def unpack_value(cls, data: bytes) -> HashXHistoryValue:
|
def unpack_value(cls, data: bytes) -> array.array:
|
||||||
a = array.array('I')
|
a = array.array('I')
|
||||||
a.frombytes(data)
|
a.frombytes(data)
|
||||||
return HashXHistoryValue(a.tolist())
|
return a
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def pack_item(cls, hashX: bytes, height: int, history: typing.List[int]):
|
def pack_item(cls, hashX: bytes, height: int, history: typing.List[int]):
|
||||||
|
|
|
@ -4,6 +4,7 @@ import hashlib
|
||||||
from bisect import bisect_right
|
from bisect import bisect_right
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from typing import NamedTuple, List
|
||||||
from lbry.testcase import CommandTestCase
|
from lbry.testcase import CommandTestCase
|
||||||
from lbry.wallet.transaction import Transaction, Output
|
from lbry.wallet.transaction import Transaction, Output
|
||||||
from lbry.schema.compat import OldClaimMessage
|
from lbry.schema.compat import OldClaimMessage
|
||||||
|
@ -11,6 +12,12 @@ from lbry.crypto.hash import sha256
|
||||||
from lbry.crypto.base58 import Base58
|
from lbry.crypto.base58 import Base58
|
||||||
|
|
||||||
|
|
||||||
|
class ClaimStateValue(NamedTuple):
|
||||||
|
claim_id: str
|
||||||
|
activation_height: int
|
||||||
|
active_in_lbrycrd: bool
|
||||||
|
|
||||||
|
|
||||||
class BaseResolveTestCase(CommandTestCase):
|
class BaseResolveTestCase(CommandTestCase):
|
||||||
|
|
||||||
async def assertResolvesToClaimId(self, name, claim_id):
|
async def assertResolvesToClaimId(self, name, claim_id):
|
||||||
|
@ -86,8 +93,6 @@ class BaseResolveTestCase(CommandTestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(len(claim_from_es[0]), 1)
|
self.assertEqual(len(claim_from_es[0]), 1)
|
||||||
self.assertEqual(claim_from_es[0][0]['claim_hash'][::-1].hex(), claim.claim_hash.hex())
|
self.assertEqual(claim_from_es[0][0]['claim_hash'][::-1].hex(), claim.claim_hash.hex())
|
||||||
|
|
||||||
|
|
||||||
self.assertEqual(claim_from_es[0][0]['claim_id'], claim.claim_hash.hex())
|
self.assertEqual(claim_from_es[0][0]['claim_id'], claim.claim_hash.hex())
|
||||||
self.assertEqual(claim_from_es[0][0]['activation_height'], claim.activation_height)
|
self.assertEqual(claim_from_es[0][0]['activation_height'], claim.activation_height)
|
||||||
self.assertEqual(claim_from_es[0][0]['last_take_over_height'], claim.last_takeover_height)
|
self.assertEqual(claim_from_es[0][0]['last_take_over_height'], claim.last_takeover_height)
|
||||||
|
@ -607,63 +612,313 @@ class ResolveClaimTakeovers(BaseResolveTestCase):
|
||||||
await self.assertNoClaimForName(name)
|
await self.assertNoClaimForName(name)
|
||||||
await self._test_activation_delay()
|
await self._test_activation_delay()
|
||||||
|
|
||||||
async def test_claim_and_update_delays(self):
|
async def create_stream_claim(self, amount: str, name='derp') -> str:
|
||||||
|
return (await self.stream_create(name, amount, allow_duplicate_name=True))['outputs'][0]['claim_id']
|
||||||
|
|
||||||
|
async def assertNameState(self, height: int, name: str, winning_claim_id: str, last_takeover_height: int,
|
||||||
|
non_winning_claims: List[ClaimStateValue]):
|
||||||
|
self.assertEqual(height, self.conductor.spv_node.server.bp.db.db_height)
|
||||||
|
await self.assertMatchClaimIsWinning(name, winning_claim_id)
|
||||||
|
for non_winning in non_winning_claims:
|
||||||
|
claim = await self.assertMatchClaim(
|
||||||
|
non_winning.claim_id, is_active_in_lbrycrd=non_winning.active_in_lbrycrd
|
||||||
|
)
|
||||||
|
self.assertEqual(non_winning.activation_height, claim.activation_height)
|
||||||
|
self.assertEqual(last_takeover_height, claim.last_takeover_height)
|
||||||
|
|
||||||
|
async def test_delay_takeover_with_update(self):
|
||||||
name = 'derp'
|
name = 'derp'
|
||||||
first_claim_id = (await self.stream_create(name, '0.2', allow_duplicate_name=True))['outputs'][0]['claim_id']
|
first_claim_id = await self.create_stream_claim('0.2', name)
|
||||||
await self.assertMatchClaimIsWinning(name, first_claim_id)
|
await self.assertMatchClaimIsWinning(name, first_claim_id)
|
||||||
await self.generate(320)
|
await self.generate(320)
|
||||||
second_claim_id = (await self.stream_create(name, '0.1', allow_duplicate_name=True))['outputs'][0]['claim_id']
|
second_claim_id = await self.create_stream_claim('0.1', name)
|
||||||
third_claim_id = (await self.stream_create(name, '0.1', allow_duplicate_name=True))['outputs'][0]['claim_id']
|
third_claim_id = await self.create_stream_claim('0.1', name)
|
||||||
|
|
||||||
await self.generate(8)
|
await self.generate(8)
|
||||||
|
await self.assertNameState(
|
||||||
self.assertEqual(537, self.conductor.spv_node.server.bp.db.db_height)
|
height=537, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
await self.assertMatchClaimIsWinning(name, first_claim_id)
|
non_winning_claims=[
|
||||||
second_claim = await self.assertMatchClaim(second_claim_id, is_active_in_lbrycrd=False)
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=False),
|
||||||
self.assertEqual(538, second_claim.activation_height)
|
ClaimStateValue(third_claim_id, activation_height=539, active_in_lbrycrd=False)
|
||||||
self.assertEqual(207, second_claim.last_takeover_height)
|
]
|
||||||
third_claim = await self.assertMatchClaim(third_claim_id, is_active_in_lbrycrd=False)
|
)
|
||||||
self.assertEqual(539, third_claim.activation_height)
|
|
||||||
self.assertEqual(207, third_claim.last_takeover_height)
|
|
||||||
|
|
||||||
await self.generate(1)
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
self.assertEqual(538, self.conductor.spv_node.server.bp.db.db_height)
|
height=538, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
await self.assertMatchClaimIsWinning(name, first_claim_id)
|
non_winning_claims=[
|
||||||
second_claim = await self.assertMatchClaim(second_claim_id)
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
self.assertEqual(538, second_claim.activation_height)
|
ClaimStateValue(third_claim_id, activation_height=539, active_in_lbrycrd=False)
|
||||||
self.assertEqual(207, second_claim.last_takeover_height)
|
]
|
||||||
third_claim = await self.assertMatchClaim(third_claim_id, is_active_in_lbrycrd=False)
|
)
|
||||||
self.assertEqual(539, third_claim.activation_height)
|
|
||||||
self.assertEqual(207, third_claim.last_takeover_height)
|
|
||||||
|
|
||||||
await self.generate(1)
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
self.assertEqual(539, self.conductor.spv_node.server.bp.db.db_height)
|
height=539, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
await self.assertMatchClaimIsWinning(name, first_claim_id)
|
non_winning_claims=[
|
||||||
second_claim = await self.assertMatchClaim(second_claim_id)
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
self.assertEqual(538, second_claim.activation_height)
|
ClaimStateValue(third_claim_id, activation_height=539, active_in_lbrycrd=True)
|
||||||
self.assertEqual(207, second_claim.last_takeover_height)
|
]
|
||||||
third_claim = await self.assertMatchClaim(third_claim_id)
|
)
|
||||||
self.assertEqual(539, third_claim.activation_height)
|
|
||||||
self.assertEqual(207, third_claim.last_takeover_height)
|
|
||||||
|
|
||||||
await self.daemon.jsonrpc_stream_update(third_claim_id, '0.21')
|
await self.daemon.jsonrpc_stream_update(third_claim_id, '0.21')
|
||||||
await self.generate(1)
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=540, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=550, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
self.assertEqual(540, self.conductor.spv_node.server.bp.db.db_height)
|
await self.generate(9)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=549, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=550, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=550, name=name, winning_claim_id=third_claim_id, last_takeover_height=550,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(first_claim_id, activation_height=207, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
async def test_delay_takeover_with_update_then_update_to_lower_before_takeover(self):
|
||||||
|
name = 'derp'
|
||||||
|
first_claim_id = await self.create_stream_claim('0.2', name)
|
||||||
await self.assertMatchClaimIsWinning(name, first_claim_id)
|
await self.assertMatchClaimIsWinning(name, first_claim_id)
|
||||||
second_claim = await self.assertMatchClaim(second_claim_id)
|
await self.generate(320)
|
||||||
self.assertEqual(538, second_claim.activation_height)
|
second_claim_id = await self.create_stream_claim('0.1', name)
|
||||||
self.assertEqual(207, second_claim.last_takeover_height)
|
third_claim_id = await self.create_stream_claim('0.1', name)
|
||||||
third_claim = await self.assertMatchClaim(third_claim_id, is_active_in_lbrycrd=False)
|
await self.generate(8)
|
||||||
self.assertEqual(550, third_claim.activation_height)
|
await self.assertNameState(
|
||||||
self.assertEqual(207, third_claim.last_takeover_height)
|
height=537, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=False),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=539, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=538, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=539, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=539, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=539, active_in_lbrycrd=True)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.daemon.jsonrpc_stream_update(third_claim_id, '0.21')
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=540, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=550, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.generate(8)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=548, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=550, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.daemon.jsonrpc_stream_update(third_claim_id, '0.09')
|
||||||
|
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=549, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=559, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
await self.generate(10)
|
await self.generate(10)
|
||||||
self.assertEqual(550, self.conductor.spv_node.server.bp.db.db_height)
|
await self.assertNameState(
|
||||||
await self.assertMatchClaimIsWinning(name, third_claim_id)
|
height=559, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=559, active_in_lbrycrd=True)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
async def test_delay_takeover_with_update_then_update_to_lower_on_takeover(self):
|
||||||
|
name = 'derp'
|
||||||
|
first_claim_id = await self.create_stream_claim('0.2', name)
|
||||||
|
await self.assertMatchClaimIsWinning(name, first_claim_id)
|
||||||
|
await self.generate(320)
|
||||||
|
second_claim_id = await self.create_stream_claim('0.1', name)
|
||||||
|
third_claim_id = await self.create_stream_claim('0.1', name)
|
||||||
|
await self.generate(8)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=537, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=False),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=539, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=538, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=539, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=539, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=539, active_in_lbrycrd=True)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.daemon.jsonrpc_stream_update(third_claim_id, '0.21')
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=540, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=550, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.generate(8)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=548, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=550, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=549, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=550, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.daemon.jsonrpc_stream_update(third_claim_id, '0.09')
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=550, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=560, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
await self.generate(10)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=560, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=560, active_in_lbrycrd=True)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
async def test_delay_takeover_with_update_then_update_to_lower_after_takeover(self):
|
||||||
|
name = 'derp'
|
||||||
|
first_claim_id = await self.create_stream_claim('0.2', name)
|
||||||
|
await self.assertMatchClaimIsWinning(name, first_claim_id)
|
||||||
|
await self.generate(320)
|
||||||
|
second_claim_id = await self.create_stream_claim('0.1', name)
|
||||||
|
third_claim_id = await self.create_stream_claim('0.1', name)
|
||||||
|
await self.generate(8)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=537, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=False),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=539, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=538, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=539, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=539, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=539, active_in_lbrycrd=True)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.daemon.jsonrpc_stream_update(third_claim_id, '0.21')
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=540, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=550, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.generate(8)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=548, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=550, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=549, name=name, winning_claim_id=first_claim_id, last_takeover_height=207,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=550, active_in_lbrycrd=False)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=550, name=name, winning_claim_id=third_claim_id, last_takeover_height=550,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(first_claim_id, activation_height=207, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.daemon.jsonrpc_stream_update(third_claim_id, '0.09')
|
||||||
|
await self.generate(1)
|
||||||
|
await self.assertNameState(
|
||||||
|
height=551, name=name, winning_claim_id=first_claim_id, last_takeover_height=551,
|
||||||
|
non_winning_claims=[
|
||||||
|
ClaimStateValue(second_claim_id, activation_height=538, active_in_lbrycrd=True),
|
||||||
|
ClaimStateValue(third_claim_id, activation_height=551, active_in_lbrycrd=True)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
async def test_resolve_signed_claims_with_fees(self):
|
async def test_resolve_signed_claims_with_fees(self):
|
||||||
channel_name = '@abc'
|
channel_name = '@abc'
|
||||||
|
|
Loading…
Reference in a new issue