258 lines
9.3 KiB
Python
258 lines
9.3 KiB
Python
import typing
|
|
from typing import Optional
|
|
from lbry.wallet.server.db.revertable import RevertablePut, RevertableDelete, RevertableOp
|
|
from lbry.wallet.server.db.prefixes import Prefixes, ClaimTakeoverValue, EffectiveAmountPrefixRow
|
|
from lbry.wallet.server.db.prefixes import RepostPrefixRow, RepostedPrefixRow
|
|
|
|
|
|
def length_encoded_name(name: str) -> bytes:
|
|
encoded = name.encode('utf-8')
|
|
return len(encoded).to_bytes(2, byteorder='big') + encoded
|
|
|
|
|
|
class StagedClaimtrieSupport(typing.NamedTuple):
|
|
claim_hash: bytes
|
|
tx_num: int
|
|
position: int
|
|
amount: int
|
|
|
|
def _get_add_remove_support_utxo_ops(self, add=True):
|
|
"""
|
|
get a list of revertable operations to add or spend a support txo to the key: value database
|
|
|
|
:param add: if true use RevertablePut operations, otherwise use RevertableDelete
|
|
:return:
|
|
"""
|
|
op = RevertablePut if add else RevertableDelete
|
|
return [
|
|
op(
|
|
*Prefixes.claim_to_support.pack_item(self.claim_hash, self.tx_num, self.position, self.amount)
|
|
),
|
|
op(
|
|
*Prefixes.support_to_claim.pack_item(self.tx_num, self.position, self.claim_hash)
|
|
)
|
|
]
|
|
|
|
def get_add_support_utxo_ops(self) -> typing.List[RevertableOp]:
|
|
return self._get_add_remove_support_utxo_ops(add=True)
|
|
|
|
def get_spend_support_txo_ops(self) -> typing.List[RevertableOp]:
|
|
return self._get_add_remove_support_utxo_ops(add=False)
|
|
|
|
|
|
class StagedActivation(typing.NamedTuple):
|
|
txo_type: int
|
|
claim_hash: bytes
|
|
tx_num: int
|
|
position: int
|
|
activation_height: int
|
|
name: str
|
|
amount: int
|
|
|
|
def _get_add_remove_activate_ops(self, add=True):
|
|
op = RevertablePut if add else RevertableDelete
|
|
# print(f"\t{'add' if add else 'remove'} {'claim' if self.txo_type == ACTIVATED_CLAIM_TXO_TYPE else 'support'},"
|
|
# f" {self.tx_num}, {self.position}, activation={self.activation_height}, {self.name}, "
|
|
# f"amount={self.amount}")
|
|
return [
|
|
op(
|
|
*Prefixes.activated.pack_item(
|
|
self.txo_type, self.tx_num, self.position, self.activation_height, self.claim_hash, self.name
|
|
)
|
|
),
|
|
op(
|
|
*Prefixes.pending_activation.pack_item(
|
|
self.activation_height, self.txo_type, self.tx_num, self.position,
|
|
self.claim_hash, self.name
|
|
)
|
|
),
|
|
op(
|
|
*Prefixes.active_amount.pack_item(
|
|
self.claim_hash, self.txo_type, self.activation_height, self.tx_num, self.position, self.amount
|
|
)
|
|
)
|
|
]
|
|
|
|
def get_activate_ops(self) -> typing.List[RevertableOp]:
|
|
return self._get_add_remove_activate_ops(add=True)
|
|
|
|
def get_remove_activate_ops(self) -> typing.List[RevertableOp]:
|
|
return self._get_add_remove_activate_ops(add=False)
|
|
|
|
|
|
def get_remove_name_ops(name: str, claim_hash: bytes, height: int) -> typing.List[RevertableDelete]:
|
|
return [
|
|
RevertableDelete(
|
|
*Prefixes.claim_takeover.pack_item(
|
|
name, claim_hash, height
|
|
)
|
|
)
|
|
]
|
|
|
|
|
|
def get_takeover_name_ops(name: str, claim_hash: bytes, takeover_height: int,
|
|
previous_winning: Optional[ClaimTakeoverValue]):
|
|
if previous_winning:
|
|
return [
|
|
RevertableDelete(
|
|
*Prefixes.claim_takeover.pack_item(
|
|
name, previous_winning.claim_hash, previous_winning.height
|
|
)
|
|
),
|
|
RevertablePut(
|
|
*Prefixes.claim_takeover.pack_item(
|
|
name, claim_hash, takeover_height
|
|
)
|
|
)
|
|
]
|
|
return [
|
|
RevertablePut(
|
|
*Prefixes.claim_takeover.pack_item(
|
|
name, claim_hash, takeover_height
|
|
)
|
|
)
|
|
]
|
|
|
|
|
|
def get_remove_effective_amount_ops(name: str, effective_amount: int, tx_num: int, position: int, claim_hash: bytes):
|
|
return [
|
|
RevertableDelete(*EffectiveAmountPrefixRow.pack_item(name, effective_amount, tx_num, position, claim_hash))
|
|
]
|
|
|
|
|
|
def get_add_effective_amount_ops(name: str, effective_amount: int, tx_num: int, position: int, claim_hash: bytes):
|
|
return [
|
|
RevertablePut(*EffectiveAmountPrefixRow.pack_item(name, effective_amount, tx_num, position, claim_hash))
|
|
]
|
|
|
|
|
|
class StagedClaimtrieItem(typing.NamedTuple):
|
|
name: str
|
|
normalized_name: str
|
|
claim_hash: bytes
|
|
amount: int
|
|
expiration_height: int
|
|
tx_num: int
|
|
position: int
|
|
root_tx_num: int
|
|
root_position: int
|
|
channel_signature_is_valid: bool
|
|
signing_hash: Optional[bytes]
|
|
reposted_claim_hash: Optional[bytes]
|
|
|
|
@property
|
|
def is_update(self) -> bool:
|
|
return (self.tx_num, self.position) != (self.root_tx_num, self.root_position)
|
|
|
|
def _get_add_remove_claim_utxo_ops(self, add=True):
|
|
"""
|
|
get a list of revertable operations to add or spend a claim txo to the key: value database
|
|
|
|
:param add: if true use RevertablePut operations, otherwise use RevertableDelete
|
|
:return:
|
|
"""
|
|
op = RevertablePut if add else RevertableDelete
|
|
ops = [
|
|
# claim tip by claim hash
|
|
op(
|
|
*Prefixes.claim_to_txo.pack_item(
|
|
self.claim_hash, self.tx_num, self.position, self.root_tx_num, self.root_position,
|
|
self.amount, self.channel_signature_is_valid, self.name
|
|
)
|
|
),
|
|
# claim hash by txo
|
|
op(
|
|
*Prefixes.txo_to_claim.pack_item(self.tx_num, self.position, self.claim_hash, self.normalized_name)
|
|
),
|
|
# claim expiration
|
|
op(
|
|
*Prefixes.claim_expiration.pack_item(
|
|
self.expiration_height, self.tx_num, self.position, self.claim_hash,
|
|
self.normalized_name
|
|
)
|
|
),
|
|
# short url resolution
|
|
]
|
|
ops.extend([
|
|
op(
|
|
*Prefixes.claim_short_id.pack_item(
|
|
self.normalized_name, self.claim_hash.hex()[:prefix_len + 1], self.root_tx_num, self.root_position,
|
|
self.tx_num, self.position
|
|
)
|
|
) for prefix_len in range(10)
|
|
])
|
|
|
|
if self.signing_hash and self.channel_signature_is_valid:
|
|
ops.extend([
|
|
# channel by stream
|
|
op(
|
|
*Prefixes.claim_to_channel.pack_item(
|
|
self.claim_hash, self.tx_num, self.position, self.signing_hash
|
|
)
|
|
),
|
|
# stream by channel
|
|
op(
|
|
*Prefixes.channel_to_claim.pack_item(
|
|
self.signing_hash, self.normalized_name, self.tx_num, self.position, self.claim_hash
|
|
)
|
|
)
|
|
])
|
|
if self.reposted_claim_hash:
|
|
ops.extend([
|
|
op(
|
|
*Prefixes.repost.pack_item(self.claim_hash, self.reposted_claim_hash)
|
|
),
|
|
op(
|
|
*Prefixes.reposted_claim.pack_item(
|
|
self.reposted_claim_hash, self.tx_num, self.position, self.claim_hash
|
|
)
|
|
),
|
|
|
|
])
|
|
return ops
|
|
|
|
def get_add_claim_utxo_ops(self) -> typing.List[RevertableOp]:
|
|
return self._get_add_remove_claim_utxo_ops(add=True)
|
|
|
|
def get_spend_claim_txo_ops(self) -> typing.List[RevertableOp]:
|
|
return self._get_add_remove_claim_utxo_ops(add=False)
|
|
|
|
def get_invalidate_signature_ops(self):
|
|
if not self.signing_hash:
|
|
return []
|
|
ops = [
|
|
RevertableDelete(
|
|
*Prefixes.claim_to_channel.pack_item(
|
|
self.claim_hash, self.tx_num, self.position, self.signing_hash
|
|
)
|
|
)
|
|
]
|
|
if self.channel_signature_is_valid:
|
|
ops.extend([
|
|
# delete channel_to_claim/claim_to_channel
|
|
RevertableDelete(
|
|
*Prefixes.channel_to_claim.pack_item(
|
|
self.signing_hash, self.normalized_name, self.tx_num, self.position, self.claim_hash
|
|
)
|
|
),
|
|
# update claim_to_txo with channel_signature_is_valid=False
|
|
RevertableDelete(
|
|
*Prefixes.claim_to_txo.pack_item(
|
|
self.claim_hash, self.tx_num, self.position, self.root_tx_num, self.root_position,
|
|
self.amount, self.channel_signature_is_valid, self.name
|
|
)
|
|
),
|
|
RevertablePut(
|
|
*Prefixes.claim_to_txo.pack_item(
|
|
self.claim_hash, self.tx_num, self.position, self.root_tx_num, self.root_position,
|
|
self.amount, False, self.name
|
|
)
|
|
)
|
|
])
|
|
return ops
|
|
|
|
def invalidate_signature(self) -> 'StagedClaimtrieItem':
|
|
return StagedClaimtrieItem(
|
|
self.name, self.normalized_name, self.claim_hash, self.amount, self.expiration_height, self.tx_num,
|
|
self.position, self.root_tx_num, self.root_position, False, None, self.reposted_claim_hash
|
|
)
|