hive-nectar 0.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hive-nectar might be problematic. Click here for more details.
- hive_nectar-0.0.2.dist-info/METADATA +182 -0
- hive_nectar-0.0.2.dist-info/RECORD +86 -0
- hive_nectar-0.0.2.dist-info/WHEEL +4 -0
- hive_nectar-0.0.2.dist-info/entry_points.txt +2 -0
- hive_nectar-0.0.2.dist-info/licenses/LICENSE.txt +23 -0
- nectar/__init__.py +32 -0
- nectar/account.py +4371 -0
- nectar/amount.py +475 -0
- nectar/asciichart.py +270 -0
- nectar/asset.py +82 -0
- nectar/block.py +446 -0
- nectar/blockchain.py +1178 -0
- nectar/blockchaininstance.py +2284 -0
- nectar/blockchainobject.py +221 -0
- nectar/blurt.py +563 -0
- nectar/cli.py +6285 -0
- nectar/comment.py +1217 -0
- nectar/community.py +513 -0
- nectar/constants.py +111 -0
- nectar/conveyor.py +309 -0
- nectar/discussions.py +1709 -0
- nectar/exceptions.py +149 -0
- nectar/hive.py +546 -0
- nectar/hivesigner.py +420 -0
- nectar/imageuploader.py +72 -0
- nectar/instance.py +129 -0
- nectar/market.py +1013 -0
- nectar/memo.py +449 -0
- nectar/message.py +357 -0
- nectar/nodelist.py +444 -0
- nectar/price.py +557 -0
- nectar/profile.py +65 -0
- nectar/rc.py +308 -0
- nectar/snapshot.py +726 -0
- nectar/steem.py +582 -0
- nectar/storage.py +53 -0
- nectar/transactionbuilder.py +622 -0
- nectar/utils.py +545 -0
- nectar/version.py +2 -0
- nectar/vote.py +557 -0
- nectar/wallet.py +472 -0
- nectar/witness.py +617 -0
- nectarapi/__init__.py +11 -0
- nectarapi/exceptions.py +123 -0
- nectarapi/graphenerpc.py +589 -0
- nectarapi/node.py +178 -0
- nectarapi/noderpc.py +229 -0
- nectarapi/rpcutils.py +97 -0
- nectarapi/version.py +2 -0
- nectarbase/__init__.py +14 -0
- nectarbase/ledgertransactions.py +75 -0
- nectarbase/memo.py +243 -0
- nectarbase/objects.py +429 -0
- nectarbase/objecttypes.py +22 -0
- nectarbase/operationids.py +102 -0
- nectarbase/operations.py +1297 -0
- nectarbase/signedtransactions.py +48 -0
- nectarbase/transactions.py +11 -0
- nectarbase/version.py +2 -0
- nectargrapheneapi/__init__.py +6 -0
- nectargraphenebase/__init__.py +27 -0
- nectargraphenebase/account.py +846 -0
- nectargraphenebase/aes.py +52 -0
- nectargraphenebase/base58.py +192 -0
- nectargraphenebase/bip32.py +494 -0
- nectargraphenebase/bip38.py +134 -0
- nectargraphenebase/chains.py +149 -0
- nectargraphenebase/dictionary.py +3 -0
- nectargraphenebase/ecdsasig.py +326 -0
- nectargraphenebase/objects.py +123 -0
- nectargraphenebase/objecttypes.py +6 -0
- nectargraphenebase/operationids.py +3 -0
- nectargraphenebase/operations.py +23 -0
- nectargraphenebase/prefix.py +11 -0
- nectargraphenebase/py23.py +38 -0
- nectargraphenebase/signedtransactions.py +201 -0
- nectargraphenebase/types.py +419 -0
- nectargraphenebase/unsignedtransactions.py +283 -0
- nectargraphenebase/version.py +2 -0
- nectarstorage/__init__.py +38 -0
- nectarstorage/base.py +306 -0
- nectarstorage/exceptions.py +16 -0
- nectarstorage/interfaces.py +237 -0
- nectarstorage/masterpassword.py +239 -0
- nectarstorage/ram.py +30 -0
- nectarstorage/sqlite.py +334 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import hashlib
|
|
3
|
+
import logging
|
|
4
|
+
import struct
|
|
5
|
+
import time
|
|
6
|
+
from binascii import hexlify
|
|
7
|
+
|
|
8
|
+
import ecdsa
|
|
9
|
+
|
|
10
|
+
from .account import PrivateKey, PublicKey
|
|
11
|
+
from .py23 import bytes_types, py23_bytes
|
|
12
|
+
|
|
13
|
+
log = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
SECP256K1_MODULE = None
|
|
16
|
+
SECP256K1_AVAILABLE = False
|
|
17
|
+
CRYPTOGRAPHY_AVAILABLE = False
|
|
18
|
+
GMPY2_MODULE = False
|
|
19
|
+
if not SECP256K1_MODULE:
|
|
20
|
+
try:
|
|
21
|
+
import secp256k1prp as secp256k1
|
|
22
|
+
|
|
23
|
+
SECP256K1_MODULE = "secp256k1"
|
|
24
|
+
SECP256K1_AVAILABLE = True
|
|
25
|
+
except:
|
|
26
|
+
try:
|
|
27
|
+
import secp256k1
|
|
28
|
+
|
|
29
|
+
SECP256K1_MODULE = "secp256k1"
|
|
30
|
+
SECP256K1_AVAILABLE = True
|
|
31
|
+
except ImportError:
|
|
32
|
+
try:
|
|
33
|
+
import cryptography
|
|
34
|
+
|
|
35
|
+
SECP256K1_MODULE = "cryptography"
|
|
36
|
+
CRYPTOGRAPHY_AVAILABLE = True
|
|
37
|
+
except ImportError:
|
|
38
|
+
SECP256K1_MODULE = "ecdsa"
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
from cryptography.exceptions import InvalidSignature
|
|
42
|
+
from cryptography.hazmat.backends import default_backend
|
|
43
|
+
from cryptography.hazmat.primitives import hashes
|
|
44
|
+
from cryptography.hazmat.primitives.asymmetric import ec
|
|
45
|
+
from cryptography.hazmat.primitives.asymmetric.utils import (
|
|
46
|
+
decode_dss_signature,
|
|
47
|
+
encode_dss_signature,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
CRYPTOGRAPHY_AVAILABLE = True
|
|
51
|
+
except ImportError:
|
|
52
|
+
CRYPTOGRAPHY_AVAILABLE = False
|
|
53
|
+
log.debug("Cryptography not available")
|
|
54
|
+
|
|
55
|
+
log.debug("Using SECP256K1 module: %s" % SECP256K1_MODULE)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _is_canonical(sig):
|
|
59
|
+
sig = bytearray(sig)
|
|
60
|
+
return (
|
|
61
|
+
not (int(sig[0]) & 0x80)
|
|
62
|
+
and not (sig[0] == 0 and not (int(sig[1]) & 0x80))
|
|
63
|
+
and not (int(sig[32]) & 0x80)
|
|
64
|
+
and not (sig[32] == 0 and not (int(sig[33]) & 0x80))
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def compressedPubkey(pk):
|
|
69
|
+
if SECP256K1_MODULE == "cryptography" and not isinstance(pk, ecdsa.keys.VerifyingKey):
|
|
70
|
+
order = ecdsa.SECP256k1.order
|
|
71
|
+
x = pk.public_numbers().x
|
|
72
|
+
y = pk.public_numbers().y
|
|
73
|
+
else:
|
|
74
|
+
order = pk.curve.generator.order()
|
|
75
|
+
p = pk.pubkey.point
|
|
76
|
+
x = p.x()
|
|
77
|
+
y = p.y()
|
|
78
|
+
x_str = ecdsa.util.number_to_string(x, order)
|
|
79
|
+
return py23_bytes(chr(2 + (y & 1)), "ascii") + x_str
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def recover_public_key(digest, signature, i, message=None):
|
|
83
|
+
"""Recover the public key from the the signature"""
|
|
84
|
+
|
|
85
|
+
# See http: //www.secg.org/download/aid-780/sec1-v2.pdf section 4.1.6 primarily
|
|
86
|
+
curve = ecdsa.SECP256k1.curve
|
|
87
|
+
G = ecdsa.SECP256k1.generator
|
|
88
|
+
order = ecdsa.SECP256k1.order
|
|
89
|
+
yp = i % 2
|
|
90
|
+
r, s = ecdsa.util.sigdecode_string(signature, order)
|
|
91
|
+
# 1.1
|
|
92
|
+
x = r + (i // 2) * order
|
|
93
|
+
# 1.3. This actually calculates for either effectively 02||X or 03||X depending on 'k' instead of always for 02||X as specified.
|
|
94
|
+
# This substitutes for the lack of reversing R later on. -R actually is defined to be just flipping the y-coordinate in the elliptic curve.
|
|
95
|
+
alpha = ((x * x * x) + (curve.a() * x) + curve.b()) % curve.p()
|
|
96
|
+
beta = ecdsa.numbertheory.square_root_mod_prime(alpha, curve.p())
|
|
97
|
+
y = beta if (beta - yp) % 2 == 0 else curve.p() - beta
|
|
98
|
+
# 1.4 Constructor of Point is supposed to check if nR is at infinity.
|
|
99
|
+
R = ecdsa.ellipticcurve.Point(curve, x, y, order)
|
|
100
|
+
# 1.5 Compute e
|
|
101
|
+
e = ecdsa.util.string_to_number(digest)
|
|
102
|
+
# 1.6 Compute Q = r^-1(sR - eG)
|
|
103
|
+
Q = ecdsa.numbertheory.inverse_mod(r, order) * (s * R + (-e % order) * G)
|
|
104
|
+
|
|
105
|
+
if SECP256K1_MODULE == "cryptography" and message is not None:
|
|
106
|
+
if not isinstance(message, bytes_types):
|
|
107
|
+
message = py23_bytes(message, "utf-8")
|
|
108
|
+
sigder = encode_dss_signature(r, s)
|
|
109
|
+
try:
|
|
110
|
+
Q_point = Q.to_affine()
|
|
111
|
+
public_key = ec.EllipticCurvePublicNumbers(
|
|
112
|
+
Q_point.x(), Q_point.y(), ec.SECP256K1()
|
|
113
|
+
).public_key(default_backend())
|
|
114
|
+
except:
|
|
115
|
+
try:
|
|
116
|
+
public_key = ec.EllipticCurvePublicNumbers(
|
|
117
|
+
Q._Point__x, Q._Point__y, ec.SECP256K1()
|
|
118
|
+
).public_key(default_backend())
|
|
119
|
+
except:
|
|
120
|
+
Q_point = Q.to_affine()
|
|
121
|
+
public_key = ec.EllipticCurvePublicNumbers(
|
|
122
|
+
int(Q_point.x()), int(Q_point.y()), ec.SECP256K1()
|
|
123
|
+
).public_key(default_backend())
|
|
124
|
+
public_key.verify(sigder, message, ec.ECDSA(hashes.SHA256()))
|
|
125
|
+
return public_key
|
|
126
|
+
else:
|
|
127
|
+
# Not strictly necessary, but let's verify the message for paranoia's sake.
|
|
128
|
+
if not ecdsa.VerifyingKey.from_public_point(Q, curve=ecdsa.SECP256k1).verify_digest(
|
|
129
|
+
signature, digest, sigdecode=ecdsa.util.sigdecode_string
|
|
130
|
+
):
|
|
131
|
+
return None
|
|
132
|
+
return ecdsa.VerifyingKey.from_public_point(Q, curve=ecdsa.SECP256k1)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def recoverPubkeyParameter(message, digest, signature, pubkey):
|
|
136
|
+
"""Use to derive a number that allows to easily recover the
|
|
137
|
+
public key from the signature
|
|
138
|
+
"""
|
|
139
|
+
if not isinstance(message, bytes_types):
|
|
140
|
+
message = py23_bytes(message, "utf-8")
|
|
141
|
+
for i in range(0, 4):
|
|
142
|
+
if SECP256K1_MODULE == "secp256k1":
|
|
143
|
+
sig = pubkey.ecdsa_recoverable_deserialize(signature, i)
|
|
144
|
+
p = secp256k1.PublicKey(pubkey.ecdsa_recover(message, sig))
|
|
145
|
+
if p.serialize() == pubkey.serialize():
|
|
146
|
+
return i
|
|
147
|
+
elif SECP256K1_MODULE == "cryptography" and not isinstance(pubkey, PublicKey):
|
|
148
|
+
p = recover_public_key(digest, signature, i, message)
|
|
149
|
+
p_comp = hexlify(compressedPubkey(p))
|
|
150
|
+
pubkey_comp = hexlify(compressedPubkey(pubkey))
|
|
151
|
+
if p_comp == pubkey_comp:
|
|
152
|
+
return i
|
|
153
|
+
else: # pragma: no cover
|
|
154
|
+
p = recover_public_key(digest, signature, i)
|
|
155
|
+
p_comp = hexlify(compressedPubkey(p))
|
|
156
|
+
p_string = hexlify(p.to_string())
|
|
157
|
+
if isinstance(pubkey, PublicKey):
|
|
158
|
+
pubkey_string = py23_bytes(repr(pubkey), "latin")
|
|
159
|
+
else: # pragma: no cover
|
|
160
|
+
pubkey_string = hexlify(pubkey.to_string())
|
|
161
|
+
if p_string == pubkey_string or p_comp == pubkey_string:
|
|
162
|
+
return i
|
|
163
|
+
return None
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def sign_message(message, wif, hashfn=hashlib.sha256):
|
|
167
|
+
"""Sign a digest with a wif key
|
|
168
|
+
|
|
169
|
+
:param str wif: Private key in
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
if not isinstance(message, bytes_types):
|
|
173
|
+
message = py23_bytes(message, "utf-8")
|
|
174
|
+
|
|
175
|
+
digest = hashfn(message).digest()
|
|
176
|
+
priv_key = PrivateKey(wif)
|
|
177
|
+
if SECP256K1_MODULE == "secp256k1":
|
|
178
|
+
p = py23_bytes(priv_key)
|
|
179
|
+
ndata = secp256k1.ffi.new("const int *ndata")
|
|
180
|
+
ndata[0] = 0
|
|
181
|
+
while True:
|
|
182
|
+
ndata[0] += 1
|
|
183
|
+
privkey = secp256k1.PrivateKey(p, raw=True)
|
|
184
|
+
sig = secp256k1.ffi.new("secp256k1_ecdsa_recoverable_signature *")
|
|
185
|
+
signed = secp256k1.lib.secp256k1_ecdsa_sign_recoverable(
|
|
186
|
+
privkey.ctx, sig, digest, privkey.private_key, secp256k1.ffi.NULL, ndata
|
|
187
|
+
)
|
|
188
|
+
if not signed == 1:
|
|
189
|
+
raise AssertionError()
|
|
190
|
+
signature, i = privkey.ecdsa_recoverable_serialize(sig)
|
|
191
|
+
if _is_canonical(signature):
|
|
192
|
+
i += 4 # compressed
|
|
193
|
+
i += 27 # compact
|
|
194
|
+
break
|
|
195
|
+
elif SECP256K1_MODULE == "cryptography":
|
|
196
|
+
cnt = 0
|
|
197
|
+
private_key = ec.derive_private_key(
|
|
198
|
+
int(repr(priv_key), 16), ec.SECP256K1(), default_backend()
|
|
199
|
+
)
|
|
200
|
+
public_key = private_key.public_key()
|
|
201
|
+
while True:
|
|
202
|
+
cnt += 1
|
|
203
|
+
if not cnt % 20:
|
|
204
|
+
log.info("Still searching for a canonical signature. Tried %d times already!" % cnt)
|
|
205
|
+
order = ecdsa.SECP256k1.order
|
|
206
|
+
sigder = private_key.sign(message, ec.ECDSA(hashes.SHA256()))
|
|
207
|
+
r, s = decode_dss_signature(sigder)
|
|
208
|
+
signature = ecdsa.util.sigencode_string(r, s, order)
|
|
209
|
+
# Make sure signature is canonical!
|
|
210
|
+
#
|
|
211
|
+
sigder = bytearray(sigder)
|
|
212
|
+
lenR = sigder[3]
|
|
213
|
+
lenS = sigder[5 + lenR]
|
|
214
|
+
if lenR == 32 and lenS == 32:
|
|
215
|
+
# Derive the recovery parameter
|
|
216
|
+
#
|
|
217
|
+
i = recoverPubkeyParameter(message, digest, signature, public_key)
|
|
218
|
+
i += 4 # compressed
|
|
219
|
+
i += 27 # compact
|
|
220
|
+
break
|
|
221
|
+
else: # pragma: no branch # pragma: no cover
|
|
222
|
+
cnt = 0
|
|
223
|
+
p = py23_bytes(priv_key)
|
|
224
|
+
sk = ecdsa.SigningKey.from_string(p, curve=ecdsa.SECP256k1)
|
|
225
|
+
while 1:
|
|
226
|
+
cnt += 1
|
|
227
|
+
if not cnt % 20:
|
|
228
|
+
log.info("Still searching for a canonical signature. Tried %d times already!" % cnt)
|
|
229
|
+
|
|
230
|
+
# Deterministic k
|
|
231
|
+
#
|
|
232
|
+
k = ecdsa.rfc6979.generate_k(
|
|
233
|
+
sk.curve.generator.order(),
|
|
234
|
+
sk.privkey.secret_multiplier,
|
|
235
|
+
hashlib.sha256,
|
|
236
|
+
hashlib.sha256(
|
|
237
|
+
digest
|
|
238
|
+
+ struct.pack("d", time.time()) # use the local time to randomize the signature
|
|
239
|
+
).digest(),
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
# Sign message
|
|
243
|
+
#
|
|
244
|
+
sigder = sk.sign_digest(digest, sigencode=ecdsa.util.sigencode_der, k=k)
|
|
245
|
+
|
|
246
|
+
# Reformating of signature
|
|
247
|
+
#
|
|
248
|
+
r, s = ecdsa.util.sigdecode_der(sigder, sk.curve.generator.order())
|
|
249
|
+
signature = ecdsa.util.sigencode_string(r, s, sk.curve.generator.order())
|
|
250
|
+
|
|
251
|
+
# Make sure signature is canonical!
|
|
252
|
+
#
|
|
253
|
+
sigder = bytearray(sigder)
|
|
254
|
+
lenR = sigder[3]
|
|
255
|
+
lenS = sigder[5 + lenR]
|
|
256
|
+
if lenR == 32 and lenS == 32:
|
|
257
|
+
# Derive the recovery parameter
|
|
258
|
+
#
|
|
259
|
+
i = recoverPubkeyParameter(message, digest, signature, sk.get_verifying_key())
|
|
260
|
+
i += 4 # compressed
|
|
261
|
+
i += 27 # compact
|
|
262
|
+
break
|
|
263
|
+
|
|
264
|
+
# pack signature
|
|
265
|
+
#
|
|
266
|
+
sigstr = struct.pack("<B", i)
|
|
267
|
+
sigstr += signature
|
|
268
|
+
|
|
269
|
+
return sigstr
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def verify_message(message, signature, hashfn=hashlib.sha256, recover_parameter=None):
|
|
273
|
+
if not isinstance(message, bytes_types):
|
|
274
|
+
message = py23_bytes(message, "utf-8")
|
|
275
|
+
if not isinstance(signature, bytes_types):
|
|
276
|
+
signature = py23_bytes(signature, "utf-8")
|
|
277
|
+
if not isinstance(message, bytes_types):
|
|
278
|
+
raise AssertionError()
|
|
279
|
+
if not isinstance(signature, bytes_types):
|
|
280
|
+
raise AssertionError()
|
|
281
|
+
digest = hashfn(message).digest()
|
|
282
|
+
sig = signature[1:]
|
|
283
|
+
if recover_parameter is None:
|
|
284
|
+
recover_parameter = bytearray(signature)[0] - 4 - 27 # recover parameter only
|
|
285
|
+
if recover_parameter < 0:
|
|
286
|
+
log.info("Could not recover parameter")
|
|
287
|
+
return None
|
|
288
|
+
|
|
289
|
+
if SECP256K1_MODULE == "secp256k1":
|
|
290
|
+
ALL_FLAGS = secp256k1.lib.SECP256K1_CONTEXT_VERIFY | secp256k1.lib.SECP256K1_CONTEXT_SIGN
|
|
291
|
+
# Placeholder
|
|
292
|
+
pub = secp256k1.PublicKey(flags=ALL_FLAGS)
|
|
293
|
+
# Recover raw signature
|
|
294
|
+
sig = pub.ecdsa_recoverable_deserialize(sig, recover_parameter)
|
|
295
|
+
# Recover PublicKey
|
|
296
|
+
verifyPub = secp256k1.PublicKey(pub.ecdsa_recover(message, sig))
|
|
297
|
+
# Convert recoverable sig to normal sig
|
|
298
|
+
normalSig = verifyPub.ecdsa_recoverable_convert(sig)
|
|
299
|
+
# Verify
|
|
300
|
+
verifyPub.ecdsa_verify(message, normalSig)
|
|
301
|
+
phex = verifyPub.serialize(compressed=True)
|
|
302
|
+
elif SECP256K1_MODULE == "cryptography":
|
|
303
|
+
p = recover_public_key(digest, sig, recover_parameter, message)
|
|
304
|
+
order = ecdsa.SECP256k1.order
|
|
305
|
+
r, s = ecdsa.util.sigdecode_string(sig, order)
|
|
306
|
+
sigder = encode_dss_signature(r, s)
|
|
307
|
+
p.verify(sigder, message, ec.ECDSA(hashes.SHA256()))
|
|
308
|
+
phex = compressedPubkey(p)
|
|
309
|
+
else: # pragma: no branch # pragma: no cover
|
|
310
|
+
p = recover_public_key(digest, sig, recover_parameter)
|
|
311
|
+
# Will throw an exception of not valid
|
|
312
|
+
p.verify_digest(sig, digest, sigdecode=ecdsa.util.sigdecode_string)
|
|
313
|
+
phex = compressedPubkey(p)
|
|
314
|
+
|
|
315
|
+
return phex
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def tweakaddPubkey(pk, digest256, SECP256K1_MODULE=SECP256K1_MODULE):
|
|
319
|
+
if SECP256K1_MODULE == "secp256k1":
|
|
320
|
+
tmp_key = secp256k1.PublicKey(pubkey=bytes(pk), raw=True)
|
|
321
|
+
new_key = tmp_key.tweak_add(digest256) # <-- add
|
|
322
|
+
raw_key = hexlify(new_key.serialize()).decode("ascii")
|
|
323
|
+
else:
|
|
324
|
+
raise Exception("Must have secp256k1 for `tweak_add`")
|
|
325
|
+
# raw_key = ecmult(pk, 1, digest256, SECP256K1_MODULE)
|
|
326
|
+
return PublicKey(raw_key, prefix=pk.prefix)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from nectargraphenebase.types import Id, JsonObj, Optional, String
|
|
5
|
+
|
|
6
|
+
from .operationids import operations
|
|
7
|
+
from .py23 import integer_types, py23_bytes, string_types
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Operation(object):
|
|
11
|
+
def __init__(self, op):
|
|
12
|
+
if isinstance(op, list) and len(op) == 2:
|
|
13
|
+
if isinstance(op[0], integer_types):
|
|
14
|
+
self.opId = op[0]
|
|
15
|
+
name = self.getOperationNameForId(self.opId)
|
|
16
|
+
else:
|
|
17
|
+
self.opId = self.operations().get(op[0], None)
|
|
18
|
+
name = op[0]
|
|
19
|
+
if self.opId is None:
|
|
20
|
+
raise ValueError("Unknown operation")
|
|
21
|
+
self.name = name[0].upper() + name[1:] # klassname
|
|
22
|
+
try:
|
|
23
|
+
klass = self._getklass(self.name)
|
|
24
|
+
except Exception:
|
|
25
|
+
raise NotImplementedError("Unimplemented Operation %s" % self.name)
|
|
26
|
+
self.op = klass(op[1])
|
|
27
|
+
self.appbase = False
|
|
28
|
+
elif isinstance(op, dict):
|
|
29
|
+
if len(op["type"]) > 10 and op["type"][-9:] == "operation":
|
|
30
|
+
name = op["type"][:-10]
|
|
31
|
+
else:
|
|
32
|
+
name = op["type"]
|
|
33
|
+
self.opId = self.operations().get(name, None)
|
|
34
|
+
if self.opId is None:
|
|
35
|
+
raise ValueError("Unknown operation")
|
|
36
|
+
self.name = name[0].upper() + name[1:] # klassname
|
|
37
|
+
try:
|
|
38
|
+
klass = self._getklass(self.name)
|
|
39
|
+
except Exception:
|
|
40
|
+
raise NotImplementedError("Unimplemented Operation %s" % self.name)
|
|
41
|
+
self.op = klass(op["value"])
|
|
42
|
+
self.appbase = True
|
|
43
|
+
else:
|
|
44
|
+
self.op = op
|
|
45
|
+
self.name = type(self.op).__name__.lower() # also store name
|
|
46
|
+
self.opId = self.operations()[self.name]
|
|
47
|
+
|
|
48
|
+
def operations(self):
|
|
49
|
+
return operations
|
|
50
|
+
|
|
51
|
+
def getOperationNameForId(self, i):
|
|
52
|
+
"""Convert an operation id into the corresponding string"""
|
|
53
|
+
for key in self.operations():
|
|
54
|
+
if int(self.operations()[key]) is int(i):
|
|
55
|
+
return key
|
|
56
|
+
return "Unknown Operation ID %d" % i
|
|
57
|
+
|
|
58
|
+
def _getklass(self, name):
|
|
59
|
+
module = __import__("graphenebase.operations", fromlist=["operations"])
|
|
60
|
+
class_ = getattr(module, name)
|
|
61
|
+
return class_
|
|
62
|
+
|
|
63
|
+
def __bytes__(self):
|
|
64
|
+
return py23_bytes(Id(self.opId)) + py23_bytes(self.op)
|
|
65
|
+
|
|
66
|
+
def __str__(self):
|
|
67
|
+
return json.dumps([self.opId, self.op.toJson()])
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class GrapheneObject(object):
|
|
71
|
+
"""Core abstraction class
|
|
72
|
+
|
|
73
|
+
This class is used for any JSON reflected object in Graphene.
|
|
74
|
+
|
|
75
|
+
* ``instance.__json__()``: encodes data into json format
|
|
76
|
+
* ``bytes(instance)``: encodes data into wire format
|
|
77
|
+
* ``str(instances)``: dumps json object as string
|
|
78
|
+
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def __init__(self, data=None):
|
|
82
|
+
self.data = data
|
|
83
|
+
|
|
84
|
+
def __bytes__(self):
|
|
85
|
+
if self.data is None:
|
|
86
|
+
return py23_bytes()
|
|
87
|
+
b = b""
|
|
88
|
+
for name, value in list(self.data.items()):
|
|
89
|
+
if isinstance(value, string_types):
|
|
90
|
+
b += py23_bytes(value, "utf-8")
|
|
91
|
+
else:
|
|
92
|
+
b += py23_bytes(value)
|
|
93
|
+
return b
|
|
94
|
+
|
|
95
|
+
def __json__(self):
|
|
96
|
+
if self.data is None:
|
|
97
|
+
return {}
|
|
98
|
+
d = {} # JSON output is *not* ordered
|
|
99
|
+
for name, value in list(self.data.items()):
|
|
100
|
+
if isinstance(value, Optional) and value.isempty():
|
|
101
|
+
continue
|
|
102
|
+
|
|
103
|
+
if isinstance(value, String):
|
|
104
|
+
d.update({name: str(value)})
|
|
105
|
+
else:
|
|
106
|
+
try:
|
|
107
|
+
d.update({name: JsonObj(value)})
|
|
108
|
+
except Exception:
|
|
109
|
+
d.update({name: value.__str__()})
|
|
110
|
+
return d
|
|
111
|
+
|
|
112
|
+
def __str__(self):
|
|
113
|
+
return json.dumps(self.__json__())
|
|
114
|
+
|
|
115
|
+
def toJson(self):
|
|
116
|
+
return self.__json__()
|
|
117
|
+
|
|
118
|
+
def json(self):
|
|
119
|
+
return self.__json__()
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def isArgsThisClass(self, args):
|
|
123
|
+
return len(args) == 1 and type(args[0]).__name__ == type(self).__name__
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from .objects import GrapheneObject, isArgsThisClass
|
|
3
|
+
from .types import (
|
|
4
|
+
Set,
|
|
5
|
+
String,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Demooepration(GrapheneObject):
|
|
10
|
+
def __init__(self, *args, **kwargs):
|
|
11
|
+
if isArgsThisClass(self, args):
|
|
12
|
+
self.data = args[0].data
|
|
13
|
+
else:
|
|
14
|
+
if len(args) == 1 and len(kwargs) == 0:
|
|
15
|
+
kwargs = args[0]
|
|
16
|
+
super(Demooepration, self).__init__(
|
|
17
|
+
OrderedDict(
|
|
18
|
+
[
|
|
19
|
+
("string", String(kwargs["string"], "account")),
|
|
20
|
+
("extensions", Set([])),
|
|
21
|
+
]
|
|
22
|
+
)
|
|
23
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
class Prefix:
|
|
3
|
+
"""This class is meant to allow changing the prefix.
|
|
4
|
+
The prefix is used to link a public key to a specific blockchain.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
prefix = "STM"
|
|
8
|
+
|
|
9
|
+
def set_prefix(self, prefix):
|
|
10
|
+
if prefix:
|
|
11
|
+
self.prefix = prefix
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
PY2 = sys.version_info[0] == 2
|
|
5
|
+
PY3 = sys.version_info[0] == 3
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
if PY3:
|
|
9
|
+
bytes_types = (bytes,)
|
|
10
|
+
string_types = (str,)
|
|
11
|
+
integer_types = (int,)
|
|
12
|
+
text_type = str
|
|
13
|
+
binary_type = bytes
|
|
14
|
+
else:
|
|
15
|
+
bytes_types = (bytes,)
|
|
16
|
+
string_types = (basestring,) # noqa: F821
|
|
17
|
+
integer_types = (int, long) # noqa: F821
|
|
18
|
+
text_type = unicode # noqa: F821
|
|
19
|
+
binary_type = str
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def py23_bytes(item=None, encoding=None):
|
|
23
|
+
if item is None:
|
|
24
|
+
return b""
|
|
25
|
+
if hasattr(item, "__bytes__"):
|
|
26
|
+
return item.__bytes__()
|
|
27
|
+
else:
|
|
28
|
+
if encoding:
|
|
29
|
+
return bytes(item, encoding)
|
|
30
|
+
else:
|
|
31
|
+
return bytes(item)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def py23_chr(item):
|
|
35
|
+
if PY2:
|
|
36
|
+
return chr(item)
|
|
37
|
+
else:
|
|
38
|
+
return bytes([item])
|