Skip to content
This repository was archived by the owner on Jan 13, 2023. It is now read-only.

Commit d69b5c9

Browse files
authored
Merge pull request #76 from iotaledger/release/2.0.0
Release/2.0.0
2 parents 220c1e0 + 2400d21 commit d69b5c9

File tree

13 files changed

+346
-203
lines changed

13 files changed

+346
-203
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ deploy:
1111
python: '3.6'
1212
tags: true
1313
provider: pypi
14-
distribution: 'bdist_wheel sdist'
14+
distributions: 'bdist_wheel sdist'
1515
skip_upload_docs: true
1616
user: phx
1717
password:

README.rst

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@
44
=====
55
PyOTA
66
=====
7-
.. warning::
8-
⚠️ This is pre-release software; it may have performance or stability issues.
9-
Please do not use this software on mainnet until v2.0.0 stable is released. ⚠️
10-
117
This is the official Python library for the IOTA Core.
128

139
It implements both the `official API`_, as well as newly-proposed functionality
@@ -32,13 +28,9 @@ PyOTA is compatible with Python 3.6, 3.5 and 2.7.
3228
============
3329
Installation
3430
============
35-
.. warning::
36-
⚠️ This is pre-release software; it may have performance or stability issues.
37-
Please do not use this software on mainnet until v2.0.0 stable is released. ⚠️
38-
3931
To install the latest version::
4032

41-
pip install --pre pyota
33+
pip install pyota
4234

4335
Optional C Extension
4436
====================
@@ -47,7 +39,7 @@ cryptography features significantly (speedups of **60x** are common!).
4739

4840
To install this extension, use the following command::
4941

50-
pip install --pre pyota[ccurl]
42+
pip install pyota[ccurl]
5143

5244

5345
Installing from Source
@@ -75,7 +67,7 @@ For the full documentation of this library, please refer to the
7567
`official API`_
7668

7769

78-
.. _Create virtualenv: https://virtualenvwrapper.readthedocs.io/
70+
.. _Create virtualenv: https://realpython.com/blog/python/python-virtual-environments-a-primer/
7971
.. _PyOTA Bug Tracker: https://github.com/iotaledger/iota.lib.py/issues
8072
.. _Slack: https://slack.iota.org/
8173
.. _dedicated forum: https://forum.iota.org/

iota/commands/extended/replay_bundle.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def _execute(self, request):
4747
minWeightMagnitude = min_weight_magnitude,
4848

4949

50-
trytes = bundle.as_tryte_strings(head_to_tail=True),
50+
trytes = bundle.as_tryte_strings(),
5151
)
5252

5353

iota/json.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from abc import ABCMeta, abstractmethod as abstract_method
66
from json.encoder import JSONEncoder as BaseJsonEncoder
7-
from typing import Mapping, Iterable
7+
from typing import Iterable, Mapping, Text
88

99
from six import with_metaclass
1010

iota/transaction/base.py

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from iota.crypto import Curl, HASH_LENGTH
1111
from iota.json import JsonSerializable
1212
from iota.transaction.types import BundleHash, Fragment, TransactionHash, \
13-
TransactionTrytes
13+
TransactionTrytes, Nonce
1414
from iota.types import Address, Hash, Tag, TryteString, TrytesCompatible, \
1515
int_from_trits, trits_from_int
1616

@@ -53,14 +53,18 @@ def from_tryte_string(cls, trytes, hash_=None):
5353
signature_message_fragment = Fragment(tryte_string[0:2187]),
5454
address = Address(tryte_string[2187:2268]),
5555
value = int_from_trits(tryte_string[2268:2295].as_trits()),
56-
tag = Tag(tryte_string[2295:2322]),
56+
legacy_tag = Tag(tryte_string[2295:2322]),
5757
timestamp = int_from_trits(tryte_string[2322:2331].as_trits()),
5858
current_index = int_from_trits(tryte_string[2331:2340].as_trits()),
5959
last_index = int_from_trits(tryte_string[2340:2349].as_trits()),
6060
bundle_hash = BundleHash(tryte_string[2349:2430]),
6161
trunk_transaction_hash = TransactionHash(tryte_string[2430:2511]),
6262
branch_transaction_hash = TransactionHash(tryte_string[2511:2592]),
63-
nonce = Hash(tryte_string[2592:2673]),
63+
tag = Tag(tryte_string[2592:2619]),
64+
attachment_timestamp = int_from_trits(tryte_string[2619:2628].as_trits()),
65+
attachment_timestamp_lower_bound = int_from_trits(tryte_string[2628:2637].as_trits()),
66+
attachment_timestamp_upper_bound = int_from_trits(tryte_string[2637:2646].as_trits()),
67+
nonce = Nonce(tryte_string[2646:2673]),
6468
)
6569

6670
def __init__(
@@ -69,16 +73,20 @@ def __init__(
6973
signature_message_fragment,
7074
address,
7175
value,
72-
tag,
7376
timestamp,
7477
current_index,
7578
last_index,
7679
bundle_hash,
7780
trunk_transaction_hash,
7881
branch_transaction_hash,
82+
tag,
83+
attachment_timestamp,
84+
attachment_timestamp_lower_bound,
85+
attachment_timestamp_upper_bound,
7986
nonce,
87+
legacy_tag = None
8088
):
81-
# type: (Optional[TransactionHash], Optional[Fragment], Address, int, Optional[Tag], int, Optional[int], Optional[int], Optional[BundleHash], Optional[TransactionHash], Optional[TransactionHash], Optional[Hash]) -> None
89+
# type: (Optional[TransactionHash], Optional[Fragment], Address, int, int, Optional[int], Optional[int], Optional[BundleHash], Optional[TransactionHash], Optional[TransactionHash], Optional[Tag], Optional[int], Optional[int], Optional[int] Optional[Hash]) -> None
8290
self.hash = hash_ # type: Optional[TransactionHash]
8391
"""
8492
Transaction ID, generated by taking a hash of the transaction
@@ -104,12 +112,12 @@ def __init__(
104112
Can be negative (i.e., for spending inputs).
105113
"""
106114

107-
self.tag = tag # type: Optional[Tag]
115+
self._legacy_tag = legacy_tag # type: Optional[Tag]
108116
"""
109-
Optional classification tag applied to this transaction.
117+
Optional classification legacy_tag applied to this transaction.
110118
"""
111119

112-
self.nonce = nonce # type: Optional[Hash]
120+
self.nonce = nonce # type: Optional[Nonce]
113121
"""
114122
Unique value used to increase security of the transaction hash.
115123
"""
@@ -154,6 +162,17 @@ def __init__(
154162
155163
The branch transaction generally has no significance.
156164
"""
165+
166+
self.tag = tag # type: Optional[Tag]
167+
"""
168+
Optional classification tag applied to this transaction.
169+
"""
170+
171+
self.attachment_timestamp = attachment_timestamp # type: int
172+
173+
self.attachment_timestamp_lower_bound = attachment_timestamp_lower_bound # type: int
174+
175+
self.attachment_timestamp_upper_bound = attachment_timestamp_upper_bound # type: int
157176

158177
self.signature_message_fragment = signature_message_fragment # type: Optional[Fragment]
159178
"""
@@ -227,6 +246,36 @@ def last_index_as_trytes(self):
227246
"""
228247
# Note that we are padding to 27 _trits_.
229248
return TryteString.from_trits(trits_from_int(self.last_index, pad=27))
249+
250+
@property
251+
def attachment_timestamp_as_trytes(self):
252+
# type: () -> TryteString
253+
"""
254+
Returns a TryteString representation of the transaction's
255+
attachment timestamp.
256+
"""
257+
#Note that we are padding to 27 _trits_.
258+
return TryteString.from_trits(trits_from_int(self.attachment_timestamp, pad=27))
259+
260+
@property
261+
def attachment_timestamp_lower_bound_as_trytes(self):
262+
# type: () -> TryteString
263+
"""
264+
Returns a TryteString representation of the transaction's
265+
attachment timestamp lower bound.
266+
"""
267+
#Note that we are padding to 27 _trits_.
268+
return TryteString.from_trits(trits_from_int(self.attachment_timestamp_lower_bound, pad=27))
269+
270+
@property
271+
def attachment_timestamp_upper_bound_as_trytes(self):
272+
# type: () -> TryteString
273+
"""
274+
Returns a TryteString representation of the transaction's
275+
attachment timestamp upper bound.
276+
"""
277+
#Note that we are padding to 27 _trits_.
278+
return TryteString.from_trits(trits_from_int(self.attachment_timestamp_upper_bound, pad=27))
230279

231280
def as_json_compatible(self):
232281
# type: () -> dict
@@ -237,18 +286,22 @@ def as_json_compatible(self):
237286
- :py:class:`iota.json.JsonEncoder`.
238287
"""
239288
return {
240-
'hash_': self.hash,
241-
'signature_message_fragment': self.signature_message_fragment,
242-
'address': self.address,
243-
'value': self.value,
244-
'tag': self.tag,
245-
'timestamp': self.timestamp,
246-
'current_index': self.current_index,
247-
'last_index': self.last_index,
248-
'bundle_hash': self.bundle_hash,
249-
'trunk_transaction_hash': self.trunk_transaction_hash,
250-
'branch_transaction_hash': self.branch_transaction_hash,
251-
'nonce': self.nonce,
289+
'hash_': self.hash,
290+
'signature_message_fragment': self.signature_message_fragment,
291+
'address': self.address,
292+
'value': self.value,
293+
'legacy_tag': self.legacy_tag,
294+
'timestamp': self.timestamp,
295+
'current_index': self.current_index,
296+
'last_index': self.last_index,
297+
'bundle_hash': self.bundle_hash,
298+
'trunk_transaction_hash': self.trunk_transaction_hash,
299+
'branch_transaction_hash': self.branch_transaction_hash,
300+
'tag': self.tag,
301+
'attachment_timestamp': self.attachment_timestamp,
302+
'attachment_timestamp_lower_bound': self.attachment_timestamp_lower_bound,
303+
'attachment_timestamp_upper_bound': self.attachment_timestamp_upper_bound,
304+
'nonce': self.nonce,
252305
}
253306

254307
def as_tryte_string(self):
@@ -260,13 +313,17 @@ def as_tryte_string(self):
260313
self.signature_message_fragment
261314
+ self.address.address
262315
+ self.value_as_trytes
263-
+ self.tag
316+
+ self.legacy_tag
264317
+ self.timestamp_as_trytes
265318
+ self.current_index_as_trytes
266319
+ self.last_index_as_trytes
267320
+ self.bundle_hash
268321
+ self.trunk_transaction_hash
269322
+ self.branch_transaction_hash
323+
+ self.tag
324+
+ self.attachment_timestamp_as_trytes
325+
+ self.attachment_timestamp_lower_bound_as_trytes
326+
+ self.attachment_timestamp_upper_bound_as_trytes
270327
+ self.nonce
271328
)
272329

@@ -279,11 +336,20 @@ def get_signature_validation_trytes(self):
279336
return (
280337
self.address.address
281338
+ self.value_as_trytes
282-
+ self.tag
339+
+ self.legacy_tag
283340
+ self.timestamp_as_trytes
284341
+ self.current_index_as_trytes
285342
+ self.last_index_as_trytes
286343
)
344+
345+
@property
346+
def legacy_tag(self):
347+
# type: () -> Tag
348+
"""
349+
Return the legacy tag of the transaction.
350+
If no legacy tag was set, returns the tag instead.
351+
"""
352+
return self._legacy_tag or self.tag
287353

288354

289355
class Bundle(JsonSerializable, Sequence[Transaction]):

iota/transaction/creation.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from iota.crypto.types import PrivateKey
1414
from iota.exceptions import with_context
1515
from iota.transaction.base import Bundle, Transaction
16-
from iota.transaction.types import BundleHash, Fragment, TransactionHash
16+
from iota.transaction.types import BundleHash, Fragment, TransactionHash, Nonce
1717
from iota.transaction.utils import get_current_timestamp
1818
from iota.types import Address, Hash, Tag, TryteString
1919

@@ -36,23 +36,26 @@ def __init__(self, address, value, tag=None, message=None, timestamp=None):
3636
timestamp = get_current_timestamp()
3737

3838
super(ProposedTransaction, self).__init__(
39-
address = address,
40-
tag = Tag(b'') if tag is None else tag,
41-
timestamp = timestamp,
42-
value = value,
39+
address = address,
40+
tag = Tag(b'') if tag is None else tag,
41+
timestamp = timestamp,
42+
value = value,
4343

4444
# These values will be populated when the bundle is finalized.
45-
bundle_hash = None,
46-
current_index = None,
47-
hash_ = None,
48-
last_index = None,
49-
signature_message_fragment = None,
45+
bundle_hash = None,
46+
current_index = None,
47+
hash_ = None,
48+
last_index = None,
49+
signature_message_fragment = None,
50+
attachment_timestamp = 0,
51+
attachment_timestamp_lower_bound = 0,
52+
attachment_timestamp_upper_bound = 0,
5053

5154
# These values start out empty; they will be populated when the
5255
# node does PoW.
53-
branch_transaction_hash = TransactionHash(b''),
54-
nonce = Hash(b''),
55-
trunk_transaction_hash = TransactionHash(b''),
56+
branch_transaction_hash = TransactionHash(b''),
57+
nonce = Nonce(b''),
58+
trunk_transaction_hash = TransactionHash(b''),
5659
)
5760

5861
self.message = TryteString(b'') if message is None else message

iota/transaction/types.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
'Fragment',
1212
'TransactionHash',
1313
'TransactionTrytes',
14+
'Nonce'
1415
]
1516

1617

@@ -72,3 +73,25 @@ def __init__(self, trytes):
7273
'trytes': trytes,
7374
},
7475
)
76+
77+
class Nonce(TryteString):
78+
"""
79+
A TryteString that acts as a transaction nonce.
80+
"""
81+
LEN = 27
82+
83+
def __init__(self, trytes):
84+
# type: (TrytesCompatible) -> None
85+
super(Nonce, self).__init__(trytes, pad=self.LEN)
86+
87+
if len(self._trytes) > self.LEN:
88+
raise with_context(
89+
exc = ValueError('{cls} values must be {len} trytes long.'.format(
90+
cls = type(self).__name__,
91+
len = self.LEN
92+
)),
93+
94+
context = {
95+
'trytes': trytes,
96+
},
97+
)

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
name = 'PyOTA',
2222
description = 'IOTA API library for Python',
2323
url = 'https://github.com/iotaledger/iota.lib.py',
24-
version = '2.0.0b2',
24+
version = '2.0.0',
2525

2626
long_description = long_description,
2727

@@ -66,7 +66,7 @@
6666
license = 'MIT',
6767

6868
classifiers = [
69-
'Development Status :: 4 - Beta',
69+
'Development Status :: 5 - Production/Stable',
7070
'Intended Audience :: Developers',
7171
'License :: OSI Approved :: MIT License',
7272
'Programming Language :: Python :: 2',

0 commit comments

Comments
 (0)