forked from LBRYCommunity/lbry-sdk
wip
This commit is contained in:
parent
0cbc514a8e
commit
ae79314869
4 changed files with 82 additions and 87 deletions
|
@ -1907,7 +1907,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
|||
pk = PrivateKey.from_bytes(
|
||||
account.ledger, Base58.decode_check(private_key)[1:-1]
|
||||
)
|
||||
tx.sign([account], {pk.address: pk})
|
||||
await tx.sign([account], {pk.address: pk})
|
||||
if not preview:
|
||||
await self.broadcast_or_release(tx, blocking)
|
||||
self.component_manager.loop.create_task(self.analytics_manager.send_credits_sent())
|
||||
|
|
|
@ -358,25 +358,27 @@ class InputScript(Script):
|
|||
REDEEM_PUBKEY_HASH = Template('pubkey_hash', (
|
||||
PUSH_SINGLE('signature'), PUSH_SINGLE('pubkey')
|
||||
))
|
||||
REDEEM_SCRIPT = Template('script', (
|
||||
MULTI_SIG_SCRIPT = Template('multi_sig', (
|
||||
SMALL_INTEGER('signatures_count'), PUSH_MANY('pubkeys'), SMALL_INTEGER('pubkeys_count'),
|
||||
OP_CHECKMULTISIG
|
||||
))
|
||||
REDEEM_SCRIPT_HASH = Template('script_hash', (
|
||||
OP_0, PUSH_MANY('signatures'), PUSH_SUBSCRIPT('script', REDEEM_SCRIPT)
|
||||
REDEEM_SCRIPT_HASH_MULTI_SIG = Template('script_hash+mult_sig', (
|
||||
PUSH_SINGLE('signature'), PUSH_SINGLE('pubkey'), PUSH_SUBSCRIPT('script', MULTI_SIG_SCRIPT)
|
||||
))
|
||||
REDEEM_TIME_LOCK = Template('timelock', (
|
||||
SMALL_INTEGER('height'), OP_CHECKLOCKTIMEVERIFY, OP_DROP,
|
||||
TIME_LOCK_SCRIPT = Template('timelock', (
|
||||
PUSH_INTEGER('height'), OP_CHECKLOCKTIMEVERIFY, OP_DROP,
|
||||
# rest is identical to OutputScript.PAY_PUBKEY_HASH:
|
||||
OP_DUP, OP_HASH160, PUSH_SINGLE('pubkey_hash'), OP_EQUALVERIFY, OP_CHECKSIG
|
||||
))
|
||||
REDEEM_SCRIPT_HASH_TIME_LOCK = Template('script_hash+timelock', (
|
||||
PUSH_SINGLE('signature'), PUSH_SINGLE('pubkey'), PUSH_SUBSCRIPT('script', TIME_LOCK_SCRIPT)
|
||||
))
|
||||
|
||||
templates = [
|
||||
REDEEM_PUBKEY,
|
||||
REDEEM_PUBKEY_HASH,
|
||||
REDEEM_SCRIPT_HASH,
|
||||
REDEEM_SCRIPT,
|
||||
REDEEM_TIME_LOCK
|
||||
REDEEM_SCRIPT_HASH_TIME_LOCK,
|
||||
REDEEM_SCRIPT_HASH_MULTI_SIG,
|
||||
]
|
||||
|
||||
@classmethod
|
||||
|
@ -387,31 +389,33 @@ class InputScript(Script):
|
|||
})
|
||||
|
||||
@classmethod
|
||||
def redeem_script_hash(cls, signatures, pubkeys):
|
||||
return cls(template=cls.REDEEM_SCRIPT_HASH, values={
|
||||
def redeem_mult_sig_script_hash(cls, signatures, pubkeys):
|
||||
return cls(template=cls.REDEEM_SCRIPT_HASH_MULTI_SIG, values={
|
||||
'signatures': signatures,
|
||||
'script': cls.redeem_script(signatures, pubkeys)
|
||||
'script': cls(template=cls.MULTI_SIG_SCRIPT, values={
|
||||
'signatures_count': len(signatures),
|
||||
'pubkeys': pubkeys,
|
||||
'pubkeys_count': len(pubkeys)
|
||||
})
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def redeem_script(cls, signatures, pubkeys):
|
||||
return cls(template=cls.REDEEM_SCRIPT, values={
|
||||
'signatures_count': len(signatures),
|
||||
'pubkeys': pubkeys,
|
||||
'pubkeys_count': len(pubkeys)
|
||||
def redeem_time_lock_script_hash(cls, signature, pubkey, height=None, pubkey_hash=None, script_source=None):
|
||||
if height and pubkey_hash:
|
||||
script = cls(template=cls.TIME_LOCK_SCRIPT, values={
|
||||
'height': height,
|
||||
'pubkey_hash': pubkey_hash
|
||||
})
|
||||
elif script_source:
|
||||
script = cls(source=script_source, template=cls.TIME_LOCK_SCRIPT)
|
||||
else:
|
||||
raise ValueError("script_source or both height and pubkey_hash are required.")
|
||||
return cls(template=cls.REDEEM_SCRIPT_HASH_TIME_LOCK, values={
|
||||
'signature': signature,
|
||||
'pubkey': pubkey,
|
||||
'script': script
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def redeem_time_lock(cls, height, pubkey_hash):
|
||||
return cls(template=cls.REDEEM_SCRIPT, values={
|
||||
'height': height,
|
||||
'pubkey_hash': pubkey_hash
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def redeem_time_lock_from_script(cls, script: bytes):
|
||||
return cls.from_source_with_template(script, cls.REDEEM_SCRIPT)
|
||||
|
||||
|
||||
class OutputScript(Script):
|
||||
|
||||
|
@ -478,21 +482,6 @@ class OutputScript(Script):
|
|||
UPDATE_CLAIM_OPCODES + PAY_SCRIPT_HASH.opcodes
|
||||
))
|
||||
|
||||
SELL_SCRIPT = Template('sell_script', (
|
||||
OP_VERIFY, OP_DROP, OP_DROP, OP_DROP, PUSH_INTEGER('price'), OP_PRICECHECK
|
||||
))
|
||||
SELL_CLAIM = Template('sell_claim+pay_script_hash', (
|
||||
OP_SELL_CLAIM, PUSH_SINGLE('claim_id'), PUSH_SUBSCRIPT('sell_script', SELL_SCRIPT),
|
||||
PUSH_SUBSCRIPT('receive_script', InputScript.REDEEM_SCRIPT), OP_2DROP, OP_2DROP
|
||||
) + PAY_SCRIPT_HASH.opcodes)
|
||||
|
||||
BUY_CLAIM = Template('buy_claim+pay_script_hash', (
|
||||
OP_BUY_CLAIM, PUSH_SINGLE('sell_id'),
|
||||
PUSH_SINGLE('claim_id'), PUSH_SINGLE('claim_version'),
|
||||
PUSH_SINGLE('owner_pubkey_hash'), PUSH_SINGLE('negotiation_signature'),
|
||||
OP_2DROP, OP_2DROP, OP_2DROP,
|
||||
) + PAY_SCRIPT_HASH.opcodes)
|
||||
|
||||
templates = [
|
||||
PAY_PUBKEY_FULL,
|
||||
PAY_PUBKEY_HASH,
|
||||
|
@ -507,8 +496,6 @@ class OutputScript(Script):
|
|||
SUPPORT_CLAIM_DATA_SCRIPT,
|
||||
UPDATE_CLAIM_PUBKEY,
|
||||
UPDATE_CLAIM_SCRIPT,
|
||||
SELL_CLAIM, SELL_SCRIPT,
|
||||
BUY_CLAIM,
|
||||
]
|
||||
|
||||
@classmethod
|
||||
|
@ -568,30 +555,6 @@ class OutputScript(Script):
|
|||
'pubkey_hash': pubkey_hash
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def sell_script(cls, price):
|
||||
return cls(template=cls.SELL_SCRIPT, values={
|
||||
'price': price,
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def sell_claim(cls, claim_id, price, signatures, pubkeys):
|
||||
return cls(template=cls.SELL_CLAIM, values={
|
||||
'claim_id': claim_id,
|
||||
'sell_script': OutputScript.sell_script(price),
|
||||
'receive_script': InputScript.redeem_script(signatures, pubkeys)
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def buy_claim(cls, sell_id, claim_id, claim_version, owner_pubkey_hash, negotiation_signature):
|
||||
return cls(template=cls.BUY_CLAIM, values={
|
||||
'sell_id': sell_id,
|
||||
'claim_id': claim_id,
|
||||
'claim_version': claim_version,
|
||||
'owner_pubkey_hash': owner_pubkey_hash,
|
||||
'negotiation_signature': negotiation_signature,
|
||||
})
|
||||
|
||||
@property
|
||||
def is_pay_pubkey_hash(self):
|
||||
return self.template.name.endswith('pay_pubkey_hash')
|
||||
|
@ -620,17 +583,6 @@ class OutputScript(Script):
|
|||
def is_support_claim_data(self):
|
||||
return self.template.name.startswith('support_claim+data+')
|
||||
|
||||
@property
|
||||
def is_sell_claim(self):
|
||||
return self.template.name.startswith('sell_claim+')
|
||||
|
||||
@property
|
||||
def is_buy_claim(self):
|
||||
return self.template.name.startswith('buy_claim+')
|
||||
|
||||
@property
|
||||
def is_claim_involved(self):
|
||||
return any((
|
||||
self.is_claim_name, self.is_support_claim, self.is_update_claim,
|
||||
self.is_sell_claim, self.is_buy_claim
|
||||
))
|
||||
return any((self.is_claim_name, self.is_support_claim, self.is_update_claim))
|
||||
|
|
|
@ -148,7 +148,9 @@ class Input(InputOutput):
|
|||
@classmethod
|
||||
def spend_time_lock(cls, txo: 'Output', script_source: bytes) -> 'Input':
|
||||
""" Create an input to spend time lock script."""
|
||||
script = InputScript.redeem_time_lock_from_script(script_source)
|
||||
script = InputScript.redeem_time_lock_script_hash(
|
||||
cls.NULL_SIGNATURE, cls.NULL_PUBLIC_KEY, script_source=script_source
|
||||
)
|
||||
return cls(txo.ref, script)
|
||||
|
||||
@property
|
||||
|
@ -867,11 +869,12 @@ class Transaction:
|
|||
assert txi.script is not None
|
||||
assert txi.txo_ref.txo is not None
|
||||
txo_script = txi.txo_ref.txo.script
|
||||
if txo_script.is_pay_pubkey_hash:
|
||||
address = ledger.hash160_to_address(txo_script.values['pubkey_hash'])
|
||||
private_key = await ledger.get_private_key_for_address(wallet, address)
|
||||
if private_key is None and extra_keys:
|
||||
private_key = extra_keys.get(address)
|
||||
if txo_script.is_pay_pubkey_hash or txo_script.is_pay_script_hash:
|
||||
if 'pubkey_hash' in txo_script.values:
|
||||
address = ledger.hash160_to_address(txo_script.values.get('pubkey_hash', ''))
|
||||
private_key = await ledger.get_private_key_for_address(wallet, address)
|
||||
else:
|
||||
private_key = next(iter(extra_keys.values()))
|
||||
assert private_key is not None, 'Cannot find private key for signing output.'
|
||||
tx = self._serialize_for_signature(i)
|
||||
txi.script.values['signature'] = \
|
||||
|
|
|
@ -262,6 +262,46 @@ class TestTransactionSerialization(unittest.TestCase):
|
|||
tx._reset()
|
||||
self.assertEqual(tx.raw, raw)
|
||||
|
||||
def test_redeem_scripthash_transaction(self):
|
||||
raw = unhexlify(
|
||||
"0200000001409223c2405238fdc516d4f2e8aa57637ce52d3b1ac42b26f1accdcda9697e79010000008a4"
|
||||
"730440220033d5286f161da717d9d1bc3c2bc28da7636b38fc0c6aefb1e0864212f05282c02205df3ce13"
|
||||
"5e79c76d44489212f77ad4e3a838562e601e6377704fa6206a6ae44f012102261773e7eebe9da80a5653d"
|
||||
"865cc600362f8e7b2b598661139dd902b5b01ea101f03aaf30ab17576a914a3328f18ac1892a6667f713d"
|
||||
"7020ff3437d973c888acfeffffff0180ed3e17000000001976a914353352b7ce1e3c9c05ffcd6ae97609d"
|
||||
"e2999744488accdf50a00"
|
||||
)
|
||||
tx = Transaction(raw)
|
||||
self.assertEqual(tx.id, 'e466881128889d1cc4110627753051c22e72a81d11229a1a1337da06940bebcf')
|
||||
self.assertEqual(tx.version, 2)
|
||||
self.assertEqual(tx.locktime, 718285,)
|
||||
self.assertEqual(len(tx.inputs), 1)
|
||||
self.assertEqual(len(tx.outputs), 1)
|
||||
|
||||
txin = tx.inputs[0]
|
||||
self.assertEqual(
|
||||
txin.txo_ref.id,
|
||||
'797e69a9cdcdacf1262bc41a3b2de57c6357aae8f2d416c5fd385240c2239240:1'
|
||||
)
|
||||
self.assertEqual(txin.txo_ref.position, 1)
|
||||
self.assertEqual(txin.sequence, 4294967294)
|
||||
self.assertIsNone(txin.coinbase)
|
||||
self.assertEqual(txin.script.template.name, 'script_hash+timelock')
|
||||
self.assertEqual(
|
||||
hexlify(txin.script.values['signature']),
|
||||
b'30440220033d5286f161da717d9d1bc3c2bc28da7636b38fc0c6aefb1e0864212f'
|
||||
b'05282c02205df3ce135e79c76d44489212f77ad4e3a838562e601e6377704fa620'
|
||||
b'6a6ae44f01'
|
||||
)
|
||||
self.assertEqual(
|
||||
hexlify(txin.script.values['pubkey']),
|
||||
b'02261773e7eebe9da80a5653d865cc600362f8e7b2b598661139dd902b5b01ea10'
|
||||
)
|
||||
script = txin.script.values['script']
|
||||
self.assertEqual(script.template.name, 'timelock')
|
||||
self.assertEqual(script.values['height'], 717738)
|
||||
self.assertEqual(hexlify(script.values['pubkey_hash']), b'a3328f18ac1892a6667f713d7020ff3437d973c8')
|
||||
|
||||
|
||||
class TestTransactionSigning(AsyncioTestCase):
|
||||
|
||||
|
|
Loading…
Reference in a new issue