diff --git a/lbrynet/wallet/__init__.py b/lbrynet/wallet/__init__.py index f5d742a87..5ed03cc18 100644 --- a/lbrynet/wallet/__init__.py +++ b/lbrynet/wallet/__init__.py @@ -1,4 +1,9 @@ -__coin__ = 'LBC' +__node_daemon__ = 'lbrycrdd' +__node_cli__ = 'lbrycrd-cli' +__node_bin__ = '' +__node_url__ = ( + 'https://github.com/lbryio/lbrycrd/releases/download/v0.12.2.1/lbrycrd-linux.zip' +) +__electrumx__ = 'lbryumx.coin.LBCRegTest' -from .coin import LBC, LBCRegTest -from .manager import LbryWalletManager +from .ledger import MainNetLedger, RegTestLedger diff --git a/lbrynet/wallet/ledger.py b/lbrynet/wallet/ledger.py index d0fe20a08..10745938b 100644 --- a/lbrynet/wallet/ledger.py +++ b/lbrynet/wallet/ledger.py @@ -7,8 +7,8 @@ from torba.baseheader import BaseHeaders, _ArithUint256 from torba.util import int_to_hex, rev_hex, hash_encode from .network import Network -from .transaction import Transaction from .database import WalletDatabase +from .transaction import Transaction class Headers(BaseHeaders): @@ -83,26 +83,38 @@ class Headers(BaseHeaders): return bnNew.GetCompact(), bnNew._value -class Ledger(BaseLedger): +class MainNetLedger(BaseLedger): name = 'LBRY Credits' symbol = 'LBC' + network_name = 'mainnet' database_class = WalletDatabase headers_class = Headers network_class = Network transaction_class = Transaction + secret_prefix = int2byte(0x1c) + pubkey_address_prefix = int2byte(0x55) + script_address_prefix = int2byte(0x7a) + extended_public_key_prefix = unhexlify('019c354f') + extended_private_key_prefix = unhexlify('019c3118') + + max_target = 0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + genesis_hash = '9c89283ba0f3227f6c03b70216b9f665f0118d5e0fa729cedf4fb34d6a34f463' + genesis_bits = 0x1f00ffff + target_timespan = 150 + default_fee_per_byte = 50 default_fee_per_name_char = 200000 def __init__(self, *args, **kwargs): - super(Ledger, self).__init__(*args, **kwargs) + super(MainNetLedger, self).__init__(*args, **kwargs) 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( - super(Ledger, self).get_transaction_base_fee(tx), + super(MainNetLedger, self).get_transaction_base_fee(tx), self.get_transaction_claim_name_fee(tx) ) @@ -117,21 +129,7 @@ class Ledger(BaseLedger): return self.network.get_values_for_uris(*uris) -class MainNetLedger(Ledger): - network_name = 'mainnet' - secret_prefix = int2byte(0x1c) - pubkey_address_prefix = int2byte(0x55) - script_address_prefix = int2byte(0x7a) - extended_public_key_prefix = unhexlify('019c354f') - extended_private_key_prefix = unhexlify('019c3118') - - max_target = 0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - genesis_hash = '9c89283ba0f3227f6c03b70216b9f665f0118d5e0fa729cedf4fb34d6a34f463' - genesis_bits = 0x1f00ffff - target_timespan = 150 - - -class TestNetLedger(Ledger): +class TestNetLedger(MainNetLedger): network_name = 'testnet' pubkey_address_prefix = int2byte(111) script_address_prefix = int2byte(196) @@ -143,7 +141,7 @@ class UnverifiedHeaders(Headers): verify_bits_to_target = False -class RegTestLedger(Ledger): +class RegTestLedger(MainNetLedger): network_name = 'regtest' headers_class = UnverifiedHeaders pubkey_address_prefix = int2byte(111) diff --git a/lbrynet/wallet/manager.py b/lbrynet/wallet/manager.py index 5dae4e2cf..2594ca7b7 100644 --- a/lbrynet/wallet/manager.py +++ b/lbrynet/wallet/manager.py @@ -8,8 +8,6 @@ from torba.constants import COIN from torba.coinselection import CoinSelector from torba.manager import WalletManager as BaseWalletManager -from .transaction import Transaction, Output, Input - class BackwardsCompatibleNetwork: def __init__(self, manager): diff --git a/lbrynet/wallet/script.py b/lbrynet/wallet/script.py new file mode 100644 index 000000000..1d8137c4b --- /dev/null +++ b/lbrynet/wallet/script.py @@ -0,0 +1,80 @@ +from torba.basescript import BaseInputScript, BaseOutputScript, Template +from torba.basescript import PUSH_SINGLE, OP_DROP, OP_2DROP + + +class InputScript(BaseInputScript): + pass + + +class OutputScript(BaseOutputScript): + + # lbry custom opcodes + OP_CLAIM_NAME = 0xb5 + OP_SUPPORT_CLAIM = 0xb6 + OP_UPDATE_CLAIM = 0xb7 + + CLAIM_NAME_OPCODES = ( + OP_CLAIM_NAME, PUSH_SINGLE('claim_name'), PUSH_SINGLE('claim'), + OP_2DROP, OP_DROP + ) + CLAIM_NAME_PUBKEY = Template('claim_name+pay_pubkey_hash', ( + CLAIM_NAME_OPCODES + BaseOutputScript.PAY_PUBKEY_HASH.opcodes + )) + CLAIM_NAME_SCRIPT = Template('claim_name+pay_script_hash', ( + CLAIM_NAME_OPCODES + BaseOutputScript.PAY_SCRIPT_HASH.opcodes + )) + + SUPPORT_CLAIM_OPCODES = ( + OP_SUPPORT_CLAIM, PUSH_SINGLE('claim_name'), PUSH_SINGLE('claim_id'), + OP_2DROP, OP_DROP + ) + SUPPORT_CLAIM_PUBKEY = Template('support_claim+pay_pubkey_hash', ( + SUPPORT_CLAIM_OPCODES + BaseOutputScript.PAY_PUBKEY_HASH.opcodes + )) + SUPPORT_CLAIM_SCRIPT = Template('support_claim+pay_script_hash', ( + SUPPORT_CLAIM_OPCODES + BaseOutputScript.PAY_SCRIPT_HASH.opcodes + )) + + UPDATE_CLAIM_OPCODES = ( + OP_UPDATE_CLAIM, PUSH_SINGLE('claim_name'), PUSH_SINGLE('claim_id'), PUSH_SINGLE('claim'), + OP_2DROP, OP_2DROP + ) + UPDATE_CLAIM_PUBKEY = Template('update_claim+pay_pubkey_hash', ( + UPDATE_CLAIM_OPCODES + BaseOutputScript.PAY_PUBKEY_HASH.opcodes + )) + UPDATE_CLAIM_SCRIPT = Template('update_claim+pay_script_hash', ( + UPDATE_CLAIM_OPCODES + BaseOutputScript.PAY_SCRIPT_HASH.opcodes + )) + + templates = BaseOutputScript.templates + [ + CLAIM_NAME_PUBKEY, + CLAIM_NAME_SCRIPT, + SUPPORT_CLAIM_PUBKEY, + SUPPORT_CLAIM_SCRIPT, + UPDATE_CLAIM_PUBKEY, + UPDATE_CLAIM_SCRIPT + ] + + @classmethod + def pay_claim_name_pubkey_hash(cls, claim_name, claim, pubkey_hash): + return cls(template=cls.CLAIM_NAME_PUBKEY, values={ + 'claim_name': claim_name, + 'claim': claim, + 'pubkey_hash': pubkey_hash + }) + + @property + def is_claim_name(self): + return self.template.name.startswith('claim_name+') + + @property + def is_support_claim(self): + return self.template.name.startswith('support_claim+') + + @property + def is_update_claim(self): + return self.template.name.startswith('update_claim+') + + @property + def is_claim_involved(self): + return self.is_claim_name or self.is_support_claim or self.is_update_claim diff --git a/lbrynet/wallet/transaction.py b/lbrynet/wallet/transaction.py new file mode 100644 index 000000000..414536aa5 --- /dev/null +++ b/lbrynet/wallet/transaction.py @@ -0,0 +1,34 @@ +import struct + +from torba.basetransaction import BaseTransaction, BaseInput, BaseOutput +from torba.hash import hash160 + +from .script import InputScript, OutputScript + + +def claim_id_hash(txid, n): + return hash160(txid + struct.pack('>I', n)) + + +class Input(BaseInput): + script_class = InputScript + + +class Output(BaseOutput): + script_class = OutputScript + + @classmethod + def pay_claim_name_pubkey_hash(cls, amount, claim_name, claim, pubkey_hash): + script = cls.script_class.pay_claim_name_pubkey_hash(claim_name, claim, pubkey_hash) + return cls(amount, script) + + +class Transaction(BaseTransaction): + + input_class = Input + output_class = Output + + def get_claim_id(self, output_index): + output = self.outputs[output_index] # type: Output + assert output.script.is_claim_name(), 'Not a name claim.' + return claim_id_hash(self.hash, output_index)