From 4d1ba50f0ade5c6297c319f8ca20119c2d40f3dd Mon Sep 17 00:00:00 2001 From: SimoneBronzini Date: Fri, 13 Jul 2018 20:30:20 +0200 Subject: [PATCH] rename TimelockScript, update README --- README.md | 61 +++++++++++++++++++++++++++++++++++++---- btcpy/structs/script.py | 8 +++--- btcpy/structs/sig.py | 2 +- tests/data/scripts.json | 2 +- tests/integration.py | 2 +- tests/unit.py | 10 +++---- 6 files changed, 68 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index e11bde3..5848cea 100644 --- a/README.md +++ b/README.md @@ -300,7 +300,7 @@ the following hierarchy * `NulldataScript` * `MultisigScript` * `IfElseScript` - * `TimelockScript` + * `AbsoluteTimelockScript` * `RelativeTimelockScript` * `Hashlock256Script` * `Hashlock160Script` @@ -468,6 +468,17 @@ Traceback (most recent call last): btcpy.structs.address.WrongScriptType: Trying to produce P2pkhAddress from P2shScript script ``` +On the other hand, addresses can also be directly converted to the scripts they represent: + +```python +>>> a = Address.from_string('mkGY1QBotzNCrpJaEsje3BpYJsktksi3gJ') +>>> a.to_script() +P2pkhScript('341e8815a2e5987d465c6c5c1fb56395cb96e400') +>>> a = Address.from_string('tb1qxs0gs9dzukv863jud3wpldtrjh9edeqqqzahcz') +>>> a.to_script() +P2wpkhScript('341e8815a2e5987d465c6c5c1fb56395cb96e400') +``` + ## Transactions ### Creating transactions @@ -486,6 +497,9 @@ methods for creation: [BIP68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki) specification. * `max()`, this automatically creates a `Sequence` object with the maximum sequence number (i.e. `0xffffffff`). +* `TimebasedSequence`, behaves like a `Sequence` but assumes the sequence expresses time. Can +also be instantiated from a `timedelta` object through its `from_timedelta` method +* `HeightBasedSequence`, behaves like a `Sequence` but assumes the sequence expresses a block height. * `ScriptSig`, this can be initialised with a `bytearray` representing the script, but offers the following static methods: * `empty()`, this creates an empty `ScriptSig`, useful when initialising a transaction @@ -499,10 +513,12 @@ sent. * `ScriptPubKey` and derived classes, they take as input a `bytearray` representing the script but can also be created through the `ScriptBuilder.identify()` method or in the way displayed later in this section. -* `Locktime`, takes as input a number representing the transaction's locktime field. +* `Locktime`, takes as input a number representing the transaction's locktime field. Can also +be constructed from a `datetime` object through its `from_datetime` method * `Transaction`, takes as inputs: a version number, a list of `TxIn`s, a list of `TxOut`s, a `Locktime`. * `SegWitTransaction`, has the same interface as `Transaction` +* `TransactionFactory` used to instantiate a generic transaction from a json or hex string All the aforementioned classes are `Immutable`, this means that, after construction, their attributes can't be mutated. This helps caching values returned by their methods. The classes @@ -511,6 +527,39 @@ attributes can't be mutated. This helps caching values returned by their methods versions are mainly used to create unsigned transactions which then are mutated to add signatures to them. We will see how to use these in the rest of this section. +Transactions can be deserialized both from json and from a hex string, see the following examples: +```python +>>> tx = Transaction.unhexlify('0100000001e4da173fbefe5e60ff63dfd38566ade407532294db655463b77a783f379ce605000000006b483045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f1012102ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2ffffffff0100c2eb0b000000001976a914df76c017354ac39bde796abe4294d31de8b5788a88ac00000000') +>>> tx.to_json() +{'hex': '0100000001e4da173fbefe5e60ff63dfd38566ade407532294db655463b77a783f379ce605000000006b483045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f1012102ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2ffffffff0100c2eb0b000000001976a914df76c017354ac39bde796abe4294d31de8b5788a88ac00000000', 'txid': 'e977c07090c2a1dcaefd3f3c4ebf4e231f4116cb272f805b0b22a85e7eece09c', 'hash': 'e977c07090c2a1dcaefd3f3c4ebf4e231f4116cb272f805b0b22a85e7eece09c', 'size': 192, 'vsize': 192, 'version': 1, 'locktime': 0, 'vin': [{'txid': '05e69c373f787ab7635465db94225307e4ad6685d3df63ff605efebe3f17dae4', 'vout': 0, 'scriptSig': {'asm': '3045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f101 02ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2', 'hex': '483045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f1012102ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2'}, 'sequence': '4294967295'}], 'vout': [{'value': '2.00000000', 'n': 0, 'scriptPubKey': {'asm': 'OP_DUP OP_HASH160 df76c017354ac39bde796abe4294d31de8b5788a OP_EQUALVERIFY OP_CHECKSIG', 'hex': '76a914df76c017354ac39bde796abe4294d31de8b5788a88ac', 'type': 'p2pkh', 'address': '1MNZwhTBHN3QTXkwob7NvhVaTVKUm7MRCg'}}]} +>>> tx = SegWitTransaction.unhexlify('0100000001e4da173fbefe5e60ff63dfd38566ade407532294db655463b77a783f379ce605000000006b483045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f1012102ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2ffffffff0100c2eb0b000000001976a914df76c017354ac39bde796abe4294d31de8b5788a88ac00000000') +Traceback (most recent call last): + File "", line 1, in + File "/home/rael/Dropbox/projects/btcpy/btcpy/structs/transaction.py", line 457, in unhexlify + return cls.deserialize(bytearray(unhexlify(string))) + File "/home/rael/Dropbox/projects/btcpy/btcpy/structs/transaction.py", line 466, in deserialize + raise TypeError('Trying to load transaction from wrong transaction serialization') +TypeError: Trying to load transaction from wrong transaction serialization +>>> tx = Transaction.from_json({'hex': '0100000001e4da173fbefe5e60ff63dfd38566ade407532294db655463b77a783f379ce605000000006b483045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f1012102ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2ffffffff0100c2eb0b000000001976a914df76c017354ac39bde796abe4294d31de8b5788a88ac00000000', 'txid': 'e977c07090c2a1dcaefd3f3c4ebf4e231f4116cb272f805b0b22a85e7eece09c', 'hash': 'e977c07090c2a1dcaefd3f3c4ebf4e231f4116cb272f805b0b22a85e7eece09c', 'size': 192, 'vsize': 192, 'version': 1, 'locktime': 0, 'vin': [{'txid': '05e69c373f787ab7635465db94225307e4ad6685d3df63ff605efebe3f17dae4', 'vout': 0, 'scriptSig': {'asm': '3045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f101 02ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2', 'hex': '483045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f1012102ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2'}, 'sequence': '4294967295'}], 'vout': [{'value': '2.00000000', 'n': 0, 'scriptPubKey': {'asm': 'OP_DUP OP_HASH160 df76c017354ac39bde796abe4294d31de8b5788a OP_EQUALVERIFY OP_CHECKSIG', 'hex': '76a914df76c017354ac39bde796abe4294d31de8b5788a88ac', 'type': 'p2pkh', 'address': '1MNZwhTBHN3QTXkwob7NvhVaTVKUm7MRCg'}}]}) +>>> tx = SegWitTransaction.from_json({'hex': '0100000001e4da173fbefe5e60ff63dfd38566ade407532294db655463b77a783f379ce605000000006b483045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f1012102ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2ffffffff0100c2eb0b000000001976a914df76c017354ac39bde796abe4294d31de8b5788a88ac00000000', 'txid': 'e977c07090c2a1dcaefd3f3c4ebf4e231f4116cb272f805b0b22a85e7eece09c', 'hash': 'e977c07090c2a1dcaefd3f3c4ebf4e231f4116cb272f805b0b22a85e7eece09c', 'size': 192, 'vsize': 192, 'version': 1, 'locktime': 0, 'vin': [{'txid': '05e69c373f787ab7635465db94225307e4ad6685d3df63ff605efebe3f17dae4', 'vout': 0, 'scriptSig': {'asm': '3045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f101 02ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2', 'hex': '483045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f1012102ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2'}, 'sequence': '4294967295'}], 'vout': [{'value': '2.00000000', 'n': 0, 'scriptPubKey': {'asm': 'OP_DUP OP_HASH160 df76c017354ac39bde796abe4294d31de8b5788a OP_EQUALVERIFY OP_CHECKSIG', 'hex': '76a914df76c017354ac39bde796abe4294d31de8b5788a88ac', 'type': 'p2pkh', 'address': '1MNZwhTBHN3QTXkwob7NvhVaTVKUm7MRCg'}}]}) +Traceback (most recent call last): + File "", line 1, in + File "/home/rael/Dropbox/projects/btcpy/btcpy/structs/transaction.py", line 737, in from_json + raise TypeError('Trying to load segwit transaction from non-segwit transaction json') +TypeError: Trying to load segwit transaction from non-segwit transaction json +``` + +As you can see from the previous example, `Transaction` and `SegWitTransaction` classes can deserialise only +json and hex strings of the appropriate type. To deserialize a generic json or hex string and build the +appropriate object, one can use the `TransactionFactory`: + +```python +>>> TransactionFactory.unhexlify('0100000001e4da173fbefe5e60ff63dfd38566ade407532294db655463b77a783f379ce605000000006b483045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f1012102ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2ffffffff0100c2eb0b000000001976a914df76c017354ac39bde796abe4294d31de8b5788a88ac00000000') + +>>> TransactionFactory.from_json({'hex': '0100000001e4da173fbefe5e60ff63dfd38566ade407532294db655463b77a783f379ce605000000006b483045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f1012102ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2ffffffff0100c2eb0b000000001976a914df76c017354ac39bde796abe4294d31de8b5788a88ac00000000', 'txid': 'e977c07090c2a1dcaefd3f3c4ebf4e231f4116cb272f805b0b22a85e7eece09c', 'hash': 'e977c07090c2a1dcaefd3f3c4ebf4e231f4116cb272f805b0b22a85e7eece09c', 'size': 192, 'vsize': 192, 'version': 1, 'locktime': 0, 'vin': [{'txid': '05e69c373f787ab7635465db94225307e4ad6685d3df63ff605efebe3f17dae4', 'vout': 0, 'scriptSig': {'asm': '3045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f101 02ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2', 'hex': '483045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f1012102ab9e8575536a1e99604a158fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2'}, 'sequence': '4294967295'}], 'vout': [{'value': '2.00000000', 'n': 0, 'scriptPubKey': {'asm': 'OP_DUP OP_HASH160 df76c017354ac39bde796abe4294d31de8b5788a OP_EQUALVERIFY OP_CHECKSIG', 'hex': '76a914df76c017354ac39bde796abe4294d31de8b5788a88ac', 'type': 'p2pkh', 'address': '1MNZwhTBHN3QTXkwob7NvhVaTVKUm7MRCg'}}]}) + +``` + Example of a transaction creation: ```python @@ -574,7 +623,7 @@ parameters: | `NulldataScript` | An OP_RETURN script | A `StackData` representing the data to store in the transaction | | `MultisigScript` | A multisig script, where m out of n keys are needed to spend | `m`, the number of signatures needed to spend this output, an arbitrary number of `PublicKeys`, `n` the number of public keys provided | | `IfElseScript` | A script consisting of an `OP_IF`, a script, an `OP_ELSE`, another script and an `OP_ENDIF` | Two `ScriptPubKey` scripts, the first to be executed in the if branch, the second to be executed in the else branch | -| `TimelockScript` | A script consisting of ` OP_CHECKLOCKTIMEVERIFY OP_DROP` and a subsequent script which can be spent only after the absolute time expressed by the `` is expired | A `Locktime`, expressing the absolute time/number of blocks after which the subsequent script can be spent, and the locked `ScriptPubKey` | +| `AbsoluteTimelockScript` | A script consisting of ` OP_CHECKLOCKTIMEVERIFY OP_DROP` and a subsequent script which can be spent only after the absolute time expressed by the `` is expired | A `Locktime`, expressing the absolute time/number of blocks after which the subsequent script can be spent, and the locked `ScriptPubKey` | | `RelativeTimelockScript` | A script consisting of ` OP_CHECKSEQUENCEVERIFY OP_DROP` and a subsequent script which can be spent only after the relative time time expressed by the `` is expired | A `Sequence`, expressing the relative time/ number of blocks after which the subsequent script can be spent, and the locked `ScriptPubKey` | | `Hashlock256Script` | A script consisting of `OP_HASH256 OP_EQUALVERIFY` and a subsequent script which can be spent only after providing the preimage of `` for the double SHA256 hash function | Either a `bytearray` or `StackData` representing the hashed value that locks the subsequent script, plus the locked `ScriptPubKey` | | `Hashlock160Script` | A script consisting of `OP_HASH160 OP_EQUALVERIFY` and a subsequent script which can be spent only after providing the preimage of `` for the RIPEMPD160 of the SHA256 hash function | Either a `bytearray` or `StackData` representing the hashed value that locks the subsequent script, plus the locked `ScriptPubKey` | @@ -610,7 +659,9 @@ Additionally, the following solvers are available and they take the following in | `P2wshV0Solver` | a `ScriptPubKey`, representing the witnessScript and a `Solver` which solves the inner witnessScript | `P2wshV0Script` | | `MultisigSolver` | an arbitrary number of `PrivateKey`s | `MultisigScript` | | `IfElseSolver` | an object of type `Branch`. This is an enum and its values are `Branch.IF` and `Branch.ELSE`, these are used to specify whether we are spending the `if` or `else` branch of the script. The second parameter is a `Solver` for the script inside the desired branch. | `IfElseScript` | -| `TimelockSolver` | a `Solver` of the inner timelocked script | `TimelockedScript`, `RelativeTimelockScript` | +| `TimelockSolver` | a `Solver` of the inner timelocked script | `AbsoluteTimelockScript`, `RelativeTimelockScript` | +| `RelativeTimelockSolver` | a `Solver` of the inner timelocked script, with absolute timelocks | `RelativeTimelockScript` | +| `AbsoluteTimelockSolver` | a `Solver` of the inner timelocked script, with relative timelocks | `AbsoluteTimelockScript` | | `HashlockSolver` | the preimage needed to spend the script, as a `bytearray`, and a `Solver` for the hashlocked script | `Hashlock256Script`, `Hashlock160Script` | @@ -820,7 +871,7 @@ Let's write the solvers for this script: >>> solver_if = IfElseSolver(Branch.IF, # branch selection ... MultisigSolver(privk, privk2)) # inner solver >>> solver_else = IfElseSolver(Branch.ELSE, -... TimelockSolver(P2pkhSolver(privk))) +... RelativeTimelockSolver(Sequence(5), P2pkhSolver(privk))) ``` ### Low-level signing diff --git a/btcpy/structs/script.py b/btcpy/structs/script.py index 4d04ee9..0772a7e 100644 --- a/btcpy/structs/script.py +++ b/btcpy/structs/script.py @@ -922,7 +922,7 @@ def type(self): # noinspection PyUnresolvedReferences -class TimelockScript(ScriptPubKey): +class AbsoluteTimelockScript(ScriptPubKey): @staticmethod def verify(bytes_): @@ -969,10 +969,10 @@ def __init__(self, *args): super().__init__(script_body.serialize()) else: - raise TypeError('Wrong number of params for TimelockScript __init__: {}'.format(len(args))) + raise TypeError('Wrong number of params for AbsoluteTimelockScript __init__: {}'.format(len(args))) def __repr__(self): - return 'TimelockScript({}, {})'.format(self.locktime, self.locked_script) + return 'AbsoluteTimelockScript({}, {})'.format(self.locktime, self.locked_script) @property def type(self): @@ -1152,7 +1152,7 @@ class ScriptBuilder(object): MultisigScript, IfElseScript, RelativeTimelockScript, - TimelockScript, + AbsoluteTimelockScript, Hashlock256Script, Hashlock160Script, P2wpkhV0Script, diff --git a/btcpy/structs/sig.py b/btcpy/structs/sig.py index 1c621c4..8b6691e 100644 --- a/btcpy/structs/sig.py +++ b/btcpy/structs/sig.py @@ -14,7 +14,7 @@ from ..lib.types import Immutable, HexSerializable from .script import (Script, P2shScript, ScriptSig, P2pkhScript, P2wpkhV0Script, P2wshV0Script, - P2pkScript, MultisigScript, TimelockScript, RelativeTimelockScript, + P2pkScript, MultisigScript, AbsoluteTimelockScript, RelativeTimelockScript, IfElseScript, HashlockScript, StackData) from ..lib.parsing import Stream diff --git a/tests/data/scripts.json b/tests/data/scripts.json index d76eba3..cb8c031 100644 --- a/tests/data/scripts.json +++ b/tests/data/scripts.json @@ -20,7 +20,7 @@ "if_else_timelock": { "hex": "6352210384478d41e71dc6c3f9edde0f928a47d1b724c05984ebfb4e7d0422e80abe95ff2103eb27fa93667e4f48e36071eb21c7229e5416ff0abd2886d59c8f314fb3cbee4052ae67037b9710b175210384478d41e71dc6c3f9edde0f928a47d1b724c05984ebfb4e7d0422e80abe95ffac68", "asm": "OP_IF OP_2 0384478d41e71dc6c3f9edde0f928a47d1b724c05984ebfb4e7d0422e80abe95ff 03eb27fa93667e4f48e36071eb21c7229e5416ff0abd2886d59c8f314fb3cbee40 OP_2 OP_CHECKMULTISIG OP_ELSE 7b9710 OP_CHECKLOCKTIMEVERIFY OP_DROP 0384478d41e71dc6c3f9edde0f928a47d1b724c05984ebfb4e7d0422e80abe95ff OP_CHECKSIG OP_ENDIF", - "code": "IfElseScript(MultisigScript(2, PublicKey.unhexlify(\"0384478d41e71dc6c3f9edde0f928a47d1b724c05984ebfb4e7d0422e80abe95ff\"), PublicKey.unhexlify(\"03eb27fa93667e4f48e36071eb21c7229e5416ff0abd2886d59c8f314fb3cbee40\"), 2), TimelockScript(Locktime(1087355), P2pkScript(PublicKey.unhexlify(\"0384478d41e71dc6c3f9edde0f928a47d1b724c05984ebfb4e7d0422e80abe95ff\"))))", + "code": "IfElseScript(MultisigScript(2, PublicKey.unhexlify(\"0384478d41e71dc6c3f9edde0f928a47d1b724c05984ebfb4e7d0422e80abe95ff\"), PublicKey.unhexlify(\"03eb27fa93667e4f48e36071eb21c7229e5416ff0abd2886d59c8f314fb3cbee40\"), 2), AbsoluteTimelockScript(Locktime(1087355), P2pkScript(PublicKey.unhexlify(\"0384478d41e71dc6c3f9edde0f928a47d1b724c05984ebfb4e7d0422e80abe95ff\"))))", "type": "if{ multisig }else{ [timelock] p2pk }" }, "relativetimelock": { diff --git a/tests/integration.py b/tests/integration.py index b328c62..6442fce 100644 --- a/tests/integration.py +++ b/tests/integration.py @@ -172,7 +172,7 @@ def get_name(): @staticmethod def get_script_cls(): - return TimelockScript + return AbsoluteTimelockScript @staticmethod def get_args(): diff --git a/tests/unit.py b/tests/unit.py index 8503c6c..ea4bf0a 100644 --- a/tests/unit.py +++ b/tests/unit.py @@ -773,7 +773,7 @@ def __init__(self, *args, **kwargs): "ad09a89e211aeb926242"))) def test_success(self): - script = TimelockScript(Locktime(self.locktime), self.locked_script) + script = AbsoluteTimelockScript(Locktime(self.locktime), self.locked_script) self.assertTrue(script.decompile() == '{} OP_CHECKLOCKTIMEVERIFY OP_DROP {}'.format(Locktime(self.locktime).for_script(), self.locked_script.decompile())) @@ -782,7 +782,7 @@ def test_success(self): def test_matching_fail_wrong_op(self): with self.assertRaises(WrongScriptTypeException): - TimelockScript.unhexlify('{}b1aa{}'.format(Locktime(self.locktime).for_script().hexlify(), + AbsoluteTimelockScript.unhexlify('{}b1aa{}'.format(Locktime(self.locktime).for_script().hexlify(), self.locked_script.hexlify())) @@ -1278,7 +1278,7 @@ def test_nested_locktimes(self): pubk = PublicKey.unhexlify('021c703de670b3b0df446e948f76acecd6e539a6a395b408bbcd711e2744b74a7b') privk = PrivateKey.unhexlify('e2cf56175f5cd5f19e9d1599b99463d769c6e16f1753dfa18aab64cbabeb7b7d') script = IfElseScript( - TimelockScript( + AbsoluteTimelockScript( Locktime(2000), RelativeTimelockScript( Sequence(5), @@ -1314,7 +1314,7 @@ def test_nested_locktimes(self): hash160 = preimage.hash160() hash256 = preimage.hash256() script = IfElseScript( - TimelockScript( + AbsoluteTimelockScript( Locktime(2000), Hashlock160Script( hash160, @@ -1322,7 +1322,7 @@ def test_nested_locktimes(self): Sequence(5), Hashlock256Script( hash256, - TimelockScript( + AbsoluteTimelockScript( Locktime(3000), RelativeTimelockScript( Sequence(10),