hive-nectar 0.2.9__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.
- hive_nectar-0.2.9.dist-info/METADATA +194 -0
- hive_nectar-0.2.9.dist-info/RECORD +87 -0
- hive_nectar-0.2.9.dist-info/WHEEL +4 -0
- hive_nectar-0.2.9.dist-info/entry_points.txt +2 -0
- hive_nectar-0.2.9.dist-info/licenses/LICENSE.txt +23 -0
- nectar/__init__.py +37 -0
- nectar/account.py +5076 -0
- nectar/amount.py +553 -0
- nectar/asciichart.py +303 -0
- nectar/asset.py +122 -0
- nectar/block.py +574 -0
- nectar/blockchain.py +1242 -0
- nectar/blockchaininstance.py +2590 -0
- nectar/blockchainobject.py +263 -0
- nectar/cli.py +5937 -0
- nectar/comment.py +1552 -0
- nectar/community.py +854 -0
- nectar/constants.py +95 -0
- nectar/discussions.py +1437 -0
- nectar/exceptions.py +152 -0
- nectar/haf.py +381 -0
- nectar/hive.py +630 -0
- nectar/imageuploader.py +114 -0
- nectar/instance.py +113 -0
- nectar/market.py +876 -0
- nectar/memo.py +542 -0
- nectar/message.py +379 -0
- nectar/nodelist.py +309 -0
- nectar/price.py +603 -0
- nectar/profile.py +74 -0
- nectar/py.typed +0 -0
- nectar/rc.py +333 -0
- nectar/snapshot.py +1024 -0
- nectar/storage.py +62 -0
- nectar/transactionbuilder.py +659 -0
- nectar/utils.py +630 -0
- nectar/version.py +3 -0
- nectar/vote.py +722 -0
- nectar/wallet.py +472 -0
- nectar/witness.py +728 -0
- nectarapi/__init__.py +12 -0
- nectarapi/exceptions.py +126 -0
- nectarapi/graphenerpc.py +596 -0
- nectarapi/node.py +194 -0
- nectarapi/noderpc.py +79 -0
- nectarapi/openapi.py +107 -0
- nectarapi/py.typed +0 -0
- nectarapi/rpcutils.py +98 -0
- nectarapi/version.py +3 -0
- nectarbase/__init__.py +15 -0
- nectarbase/ledgertransactions.py +106 -0
- nectarbase/memo.py +242 -0
- nectarbase/objects.py +521 -0
- nectarbase/objecttypes.py +21 -0
- nectarbase/operationids.py +102 -0
- nectarbase/operations.py +1357 -0
- nectarbase/py.typed +0 -0
- nectarbase/signedtransactions.py +89 -0
- nectarbase/transactions.py +11 -0
- nectarbase/version.py +3 -0
- nectargraphenebase/__init__.py +27 -0
- nectargraphenebase/account.py +1121 -0
- nectargraphenebase/aes.py +49 -0
- nectargraphenebase/base58.py +197 -0
- nectargraphenebase/bip32.py +575 -0
- nectargraphenebase/bip38.py +110 -0
- nectargraphenebase/chains.py +15 -0
- nectargraphenebase/dictionary.py +2 -0
- nectargraphenebase/ecdsasig.py +309 -0
- nectargraphenebase/objects.py +130 -0
- nectargraphenebase/objecttypes.py +8 -0
- nectargraphenebase/operationids.py +5 -0
- nectargraphenebase/operations.py +25 -0
- nectargraphenebase/prefix.py +13 -0
- nectargraphenebase/py.typed +0 -0
- nectargraphenebase/signedtransactions.py +221 -0
- nectargraphenebase/types.py +557 -0
- nectargraphenebase/unsignedtransactions.py +288 -0
- nectargraphenebase/version.py +3 -0
- nectarstorage/__init__.py +57 -0
- nectarstorage/base.py +317 -0
- nectarstorage/exceptions.py +15 -0
- nectarstorage/interfaces.py +244 -0
- nectarstorage/masterpassword.py +237 -0
- nectarstorage/py.typed +0 -0
- nectarstorage/ram.py +27 -0
- nectarstorage/sqlite.py +343 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import logging
|
|
3
|
+
from binascii import hexlify, unhexlify
|
|
4
|
+
from collections import OrderedDict
|
|
5
|
+
from typing import Any, Dict, List, Optional, Union
|
|
6
|
+
|
|
7
|
+
import ecdsa
|
|
8
|
+
from cryptography.exceptions import InvalidSignature
|
|
9
|
+
|
|
10
|
+
from .account import PublicKey
|
|
11
|
+
from .chains import known_chains
|
|
12
|
+
from .ecdsasig import sign_message, verify_message
|
|
13
|
+
from .objects import GrapheneObject, Operation, isArgsThisClass
|
|
14
|
+
from .types import (
|
|
15
|
+
Array,
|
|
16
|
+
PointInTime,
|
|
17
|
+
Set,
|
|
18
|
+
Signature,
|
|
19
|
+
Uint16,
|
|
20
|
+
Uint32,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
log = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Signed_Transaction(GrapheneObject):
|
|
27
|
+
"""Create a signed transaction and offer method to create the
|
|
28
|
+
signature
|
|
29
|
+
|
|
30
|
+
:param num ref_block_num: reference block number
|
|
31
|
+
:param num ref_block_prefix:
|
|
32
|
+
:param str expiration: expiration date
|
|
33
|
+
:param array operations: array of operations
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
37
|
+
if isArgsThisClass(self, args):
|
|
38
|
+
self.data = args[0].data
|
|
39
|
+
else:
|
|
40
|
+
if len(args) == 1 and len(kwargs) == 0:
|
|
41
|
+
kwargs = args[0]
|
|
42
|
+
# Remove prefix from kwargs if present (not used in this context)
|
|
43
|
+
kwargs.pop("prefix", None)
|
|
44
|
+
if "extensions" not in kwargs:
|
|
45
|
+
kwargs["extensions"] = Set([])
|
|
46
|
+
elif not kwargs.get("extensions"):
|
|
47
|
+
kwargs["extensions"] = Set([])
|
|
48
|
+
if "signatures" not in kwargs:
|
|
49
|
+
kwargs["signatures"] = Array([])
|
|
50
|
+
else:
|
|
51
|
+
# Defensive: if a string, wrap in a list and log warning
|
|
52
|
+
sigs = kwargs["signatures"]
|
|
53
|
+
if isinstance(sigs, str):
|
|
54
|
+
raise TypeError(
|
|
55
|
+
"signatures parameter must be a list of signature strings, not a string. "
|
|
56
|
+
f"Did you mean to pass [{sigs!r}]?"
|
|
57
|
+
)
|
|
58
|
+
kwargs["signatures"] = Array([Signature(unhexlify(a)) for a in sigs])
|
|
59
|
+
|
|
60
|
+
if "operations" in kwargs:
|
|
61
|
+
opklass = self.getOperationKlass()
|
|
62
|
+
if all([not isinstance(a, opklass) for a in kwargs["operations"]]):
|
|
63
|
+
kwargs["operations"] = Array([opklass(a) for a in kwargs["operations"]])
|
|
64
|
+
else:
|
|
65
|
+
kwargs["operations"] = Array(kwargs["operations"])
|
|
66
|
+
|
|
67
|
+
super().__init__(
|
|
68
|
+
OrderedDict(
|
|
69
|
+
[
|
|
70
|
+
("ref_block_num", Uint16(kwargs["ref_block_num"])),
|
|
71
|
+
("ref_block_prefix", Uint32(kwargs["ref_block_prefix"])),
|
|
72
|
+
("expiration", PointInTime(kwargs["expiration"])),
|
|
73
|
+
("operations", kwargs["operations"]),
|
|
74
|
+
("extensions", kwargs["extensions"]),
|
|
75
|
+
("signatures", kwargs["signatures"]),
|
|
76
|
+
]
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def id(self) -> str:
|
|
82
|
+
"""The transaction id of this transaction"""
|
|
83
|
+
# Store signatures temporarily since they are not part of
|
|
84
|
+
# transaction id
|
|
85
|
+
sigs = self.data["signatures"]
|
|
86
|
+
self.data.pop("signatures", None)
|
|
87
|
+
|
|
88
|
+
# Generage Hash of the seriliazed version
|
|
89
|
+
h = hashlib.sha256(bytes(self)).digest()
|
|
90
|
+
|
|
91
|
+
# recover signatures
|
|
92
|
+
self.data["signatures"] = sigs
|
|
93
|
+
|
|
94
|
+
# Return properly truncated tx hash
|
|
95
|
+
return hexlify(h[:20]).decode("ascii")
|
|
96
|
+
|
|
97
|
+
def getOperationKlass(self) -> type[Operation]:
|
|
98
|
+
return Operation
|
|
99
|
+
|
|
100
|
+
def derSigToHexSig(self, s: bytes) -> str:
|
|
101
|
+
"""Format DER to HEX signature"""
|
|
102
|
+
s, junk = ecdsa.der.remove_sequence(unhexlify(s))
|
|
103
|
+
if junk:
|
|
104
|
+
log.debug("JUNK: %s", hexlify(junk).decode("ascii"))
|
|
105
|
+
if not (junk == b""):
|
|
106
|
+
raise AssertionError()
|
|
107
|
+
x, s = ecdsa.der.remove_integer(s)
|
|
108
|
+
y, s = ecdsa.der.remove_integer(s)
|
|
109
|
+
return "{:064x}{:064x}".format(x, y)
|
|
110
|
+
|
|
111
|
+
def getKnownChains(self) -> Dict[str, Any]:
|
|
112
|
+
return known_chains
|
|
113
|
+
|
|
114
|
+
def getChainParams(self, chain: Union[str, Dict[str, Any]]) -> Dict[str, Any]:
|
|
115
|
+
# Which network are we on:
|
|
116
|
+
chains = self.getKnownChains()
|
|
117
|
+
if isinstance(chain, str) and chain in chains:
|
|
118
|
+
chain_params = chains[chain]
|
|
119
|
+
elif isinstance(chain, dict):
|
|
120
|
+
chain_params = chain
|
|
121
|
+
else:
|
|
122
|
+
raise Exception("sign() only takes a string or a dict as chain!")
|
|
123
|
+
if "chain_id" not in chain_params:
|
|
124
|
+
raise Exception("sign() needs a 'chain_id' in chain params!")
|
|
125
|
+
return chain_params
|
|
126
|
+
|
|
127
|
+
def deriveDigest(self, chain: Union[str, Dict[str, Any]]) -> None:
|
|
128
|
+
chain_params = self.getChainParams(chain)
|
|
129
|
+
# Chain ID
|
|
130
|
+
self.chainid = chain_params["chain_id"]
|
|
131
|
+
|
|
132
|
+
# Do not serialize signatures
|
|
133
|
+
sigs = self.data["signatures"]
|
|
134
|
+
self.data["signatures"] = []
|
|
135
|
+
|
|
136
|
+
# Get message to sign
|
|
137
|
+
# bytes(self) will give the wire formated data according to
|
|
138
|
+
# GrapheneObject and the data given in __init__()
|
|
139
|
+
self.message = unhexlify(self.chainid) + bytes(self)
|
|
140
|
+
self.digest = hashlib.sha256(self.message).digest()
|
|
141
|
+
|
|
142
|
+
# restore signatures
|
|
143
|
+
self.data["signatures"] = sigs
|
|
144
|
+
|
|
145
|
+
def verify(
|
|
146
|
+
self,
|
|
147
|
+
pubkeys: Optional[List[Any]] = None,
|
|
148
|
+
chain: Optional[Union[str, Dict[str, Any]]] = None,
|
|
149
|
+
recover_parameter: bool = False,
|
|
150
|
+
) -> List[Any]:
|
|
151
|
+
"""Returned pubkeys have to be checked if they are existing"""
|
|
152
|
+
if not chain:
|
|
153
|
+
raise ValueError("chain parameter is required")
|
|
154
|
+
chain_params = self.getChainParams(chain)
|
|
155
|
+
self.deriveDigest(chain)
|
|
156
|
+
signatures = self.data["signatures"].data
|
|
157
|
+
pubKeysFound = []
|
|
158
|
+
|
|
159
|
+
for signature in signatures:
|
|
160
|
+
p = None
|
|
161
|
+
if recover_parameter:
|
|
162
|
+
try:
|
|
163
|
+
p = verify_message(self.message, bytes(signature))
|
|
164
|
+
except (ValueError, AssertionError, ecdsa.keys.BadSignatureError, InvalidSignature):
|
|
165
|
+
p = None
|
|
166
|
+
|
|
167
|
+
if p is None:
|
|
168
|
+
for i in range(4):
|
|
169
|
+
try:
|
|
170
|
+
p = verify_message(self.message, bytes(signature), recover_parameter=i)
|
|
171
|
+
if p is not None:
|
|
172
|
+
phex = hexlify(p).decode("ascii")
|
|
173
|
+
pubKeysFound.append(phex)
|
|
174
|
+
except (
|
|
175
|
+
ValueError,
|
|
176
|
+
AssertionError,
|
|
177
|
+
ecdsa.keys.BadSignatureError,
|
|
178
|
+
InvalidSignature,
|
|
179
|
+
) as e:
|
|
180
|
+
log.debug("Signature recovery failed for parameter %d: %s", i, e)
|
|
181
|
+
p = None
|
|
182
|
+
else:
|
|
183
|
+
phex = hexlify(p).decode("ascii")
|
|
184
|
+
pubKeysFound.append(phex)
|
|
185
|
+
|
|
186
|
+
for pubkey in pubkeys or []:
|
|
187
|
+
if not isinstance(pubkey, PublicKey):
|
|
188
|
+
raise Exception("Pubkeys must be array of 'PublicKey'")
|
|
189
|
+
|
|
190
|
+
k = pubkey.unCompressed()[2:]
|
|
191
|
+
if k not in pubKeysFound and repr(pubkey) not in pubKeysFound:
|
|
192
|
+
k = PublicKey(PublicKey(k).compressed())
|
|
193
|
+
f = format(k, chain_params["prefix"])
|
|
194
|
+
raise Exception("Signature for %s missing!" % f)
|
|
195
|
+
return pubKeysFound
|
|
196
|
+
|
|
197
|
+
def sign(
|
|
198
|
+
self, wifkeys: Union[str, List[str]], chain: Optional[Union[str, Dict[str, Any]]] = None
|
|
199
|
+
) -> "Signed_Transaction":
|
|
200
|
+
"""Sign the transaction with the provided private keys.
|
|
201
|
+
|
|
202
|
+
:param array wifkeys: Array of wif keys
|
|
203
|
+
:param str chain: identifier for the chain
|
|
204
|
+
|
|
205
|
+
"""
|
|
206
|
+
if not chain:
|
|
207
|
+
raise Exception("Chain needs to be provided!")
|
|
208
|
+
self.deriveDigest(chain)
|
|
209
|
+
|
|
210
|
+
# Get Unique private keys
|
|
211
|
+
# Preserve order while removing duplicates (Python 3.7+ dicts maintain insertion order)
|
|
212
|
+
self.privkeys = list(dict.fromkeys(wifkeys if isinstance(wifkeys, list) else [wifkeys]))
|
|
213
|
+
|
|
214
|
+
# Sign the message with every private key given!
|
|
215
|
+
sigs = []
|
|
216
|
+
for wif in self.privkeys:
|
|
217
|
+
signature = sign_message(self.message, wif)
|
|
218
|
+
sigs.append(Signature(signature))
|
|
219
|
+
|
|
220
|
+
self.data["signatures"] = Array(sigs)
|
|
221
|
+
return self
|