lbry-sdk/lbrynet/wallet/ledger.py

189 lines
6.4 KiB
Python
Raw Normal View History

2018-07-10 06:30:13 +02:00
import logging
2018-06-12 17:53:29 +02:00
import struct
2018-07-10 06:30:13 +02:00
2018-06-12 17:53:29 +02:00
from six import int2byte
from binascii import unhexlify
2018-07-12 05:18:59 +02:00
from twisted.internet import defer
from .resolve import Resolver
from lbryschema.error import URIParseError
2018-07-10 06:30:13 +02:00
from lbryschema.uri import parse_lbry_uri
2018-05-26 05:26:07 +02:00
from torba.baseledger import BaseLedger
2018-06-12 17:53:29 +02:00
from torba.baseheader import BaseHeaders, _ArithUint256
from torba.util import int_to_hex, rev_hex, hash_encode
2018-07-05 04:16:02 +02:00
from .account import Account
from .network import Network
2018-06-12 17:53:29 +02:00
from .database import WalletDatabase
2018-06-14 06:53:38 +02:00
from .transaction import Transaction
2018-07-10 06:30:13 +02:00
log = logging.getLogger(__name__)
2018-06-12 17:53:29 +02:00
class Headers(BaseHeaders):
header_size = 112
2018-06-12 17:53:29 +02:00
@staticmethod
def _serialize(header):
return b''.join([
int_to_hex(header['version'], 4),
rev_hex(header['prev_block_hash']),
rev_hex(header['merkle_root']),
rev_hex(header['claim_trie_root']),
int_to_hex(int(header['timestamp']), 4),
int_to_hex(int(header['bits']), 4),
int_to_hex(int(header['nonce']), 4)
])
@staticmethod
def _deserialize(height, header):
version, = struct.unpack('<I', header[:4])
timestamp, bits, nonce = struct.unpack('<III', header[100:112])
return {
'version': version,
'prev_block_hash': hash_encode(header[4:36]),
'merkle_root': hash_encode(header[36:68]),
'claim_trie_root': hash_encode(header[68:100]),
'timestamp': timestamp,
'bits': bits,
'nonce': nonce,
'block_height': height,
}
2018-07-10 06:30:13 +02:00
@property
def claim_trie_root(self, height=None):
height = self.height if height is None else height
return self[height]['claim_trie_root']
2018-06-12 17:53:29 +02:00
def _calculate_next_work_required(self, height, first, last):
""" See: lbrycrd/src/lbry.cpp """
if height == 0:
return self.ledger.genesis_bits, self.ledger.max_target
if self.verify_bits_to_target:
bits = last['bits']
bitsN = (bits >> 24) & 0xff
assert 0x03 <= bitsN <= 0x1f, \
"First part of bits should be in [0x03, 0x1d], but it was {}".format(hex(bitsN))
bitsBase = bits & 0xffffff
assert 0x8000 <= bitsBase <= 0x7fffff, \
"Second part of bits should be in [0x8000, 0x7fffff] but it was {}".format(bitsBase)
# new target
retargetTimespan = self.ledger.target_timespan
nActualTimespan = last['timestamp'] - first['timestamp']
nModulatedTimespan = retargetTimespan + (nActualTimespan - retargetTimespan) // 8
nMinTimespan = retargetTimespan - (retargetTimespan // 8)
nMaxTimespan = retargetTimespan + (retargetTimespan // 2)
# Limit adjustment step
if nModulatedTimespan < nMinTimespan:
nModulatedTimespan = nMinTimespan
elif nModulatedTimespan > nMaxTimespan:
nModulatedTimespan = nMaxTimespan
# Retarget
bnPowLimit = _ArithUint256(self.ledger.max_target)
bnNew = _ArithUint256.SetCompact(last['bits'])
bnNew *= nModulatedTimespan
bnNew //= nModulatedTimespan
if bnNew > bnPowLimit:
bnNew = bnPowLimit
return bnNew.GetCompact(), bnNew._value
2018-06-14 06:53:38 +02:00
class MainNetLedger(BaseLedger):
2018-06-12 17:53:29 +02:00
name = 'LBRY Credits'
symbol = 'LBC'
2018-06-14 06:53:38 +02:00
network_name = 'mainnet'
2018-06-12 17:53:29 +02:00
2018-07-05 04:16:02 +02:00
account_class = Account
2018-06-12 17:53:29 +02:00
database_class = WalletDatabase
headers_class = Headers
network_class = Network
transaction_class = Transaction
2018-06-14 06:53:38 +02:00
secret_prefix = int2byte(0x1c)
pubkey_address_prefix = int2byte(0x55)
script_address_prefix = int2byte(0x7a)
2018-07-01 23:21:18 +02:00
extended_public_key_prefix = unhexlify('0488b21e')
extended_private_key_prefix = unhexlify('0488ade4')
2018-06-14 06:53:38 +02:00
max_target = 0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
genesis_hash = '9c89283ba0f3227f6c03b70216b9f665f0118d5e0fa729cedf4fb34d6a34f463'
genesis_bits = 0x1f00ffff
target_timespan = 150
2018-06-12 17:53:29 +02:00
default_fee_per_byte = 50
default_fee_per_name_char = 200000
def __init__(self, *args, **kwargs):
2018-06-14 06:53:38 +02:00
super(MainNetLedger, self).__init__(*args, **kwargs)
2018-06-12 17:53:29 +02:00
self.fee_per_name_char = self.config.get('fee_per_name_char', self.default_fee_per_name_char)
def get_transaction_base_fee(self, tx):
""" Fee for the transaction header and all outputs; without inputs. """
return max(
2018-06-14 06:53:38 +02:00
super(MainNetLedger, self).get_transaction_base_fee(tx),
2018-06-12 17:53:29 +02:00
self.get_transaction_claim_name_fee(tx)
)
def get_transaction_claim_name_fee(self, tx):
fee = 0
for output in tx.outputs:
if output.script.is_claim_name:
fee += len(output.script.values['claim_name']) * self.fee_per_name_char
return fee
2018-07-10 06:30:13 +02:00
@defer.inlineCallbacks
def resolve(self, page, page_size, *uris):
for uri in uris:
try:
parse_lbry_uri(uri)
except URIParseError as err:
defer.returnValue({'error': err.message})
resolutions = yield self.network.get_values_for_uris(self.headers.hash(), *uris)
resolver = Resolver(self.headers.claim_trie_root, self.headers.height, self.transaction_class,
hash160_to_address=lambda x: self.hash160_to_address(x), network=self.network)
defer.returnValue((yield resolver._handle_resolutions(resolutions, uris, page, page_size)))
2018-06-12 17:53:29 +02:00
2018-07-12 05:18:59 +02:00
@defer.inlineCallbacks
def start(self):
yield super(MainNetLedger, self).start()
yield defer.DeferredList([
a.maybe_migrate_certificates() for a in self.accounts
])
2018-06-12 17:53:29 +02:00
2018-06-14 06:53:38 +02:00
class TestNetLedger(MainNetLedger):
2018-06-12 17:53:29 +02:00
network_name = 'testnet'
pubkey_address_prefix = int2byte(111)
script_address_prefix = int2byte(196)
extended_public_key_prefix = unhexlify('043587cf')
extended_private_key_prefix = unhexlify('04358394')
2018-06-12 17:53:29 +02:00
class UnverifiedHeaders(Headers):
verify_bits_to_target = False
2018-06-14 06:53:38 +02:00
class RegTestLedger(MainNetLedger):
2018-06-12 17:53:29 +02:00
network_name = 'regtest'
headers_class = UnverifiedHeaders
pubkey_address_prefix = int2byte(111)
script_address_prefix = int2byte(196)
extended_public_key_prefix = unhexlify('043587cf')
extended_private_key_prefix = unhexlify('04358394')
max_target = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
genesis_hash = '6e3fcf1299d4ec5d79c3a4c91d624a4acf9e2e173d95a1a0504f677669687556'
genesis_bits = 0x207fffff
target_timespan = 1