graphsense-python 2.18.0__py3-none-any.whl → 2.19.0__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.
- graphsense/__init__.py +5 -7
- graphsense/address_scan/validators.py +93 -24
- graphsense/api/__init__.py +0 -1
- graphsense/api/addresses_api.py +0 -303
- graphsense/api/general_api.py +3 -3
- graphsense/api_client.py +1 -1
- graphsense/cli/raw.py +21 -1
- graphsense/configuration.py +2 -2
- graphsense/ext/client.py +10 -6
- graphsense/ext/output.py +2 -2
- graphsense/models/__init__.py +1 -2
- graphsense/models/address.py +1 -1
- graphsense/models/capabilities.py +14 -4
- graphsense/models/{neighbor_entities.py → service_info.py} +20 -18
- graphsense/removed.py +146 -0
- {graphsense_python-2.18.0.dist-info → graphsense_python-2.19.0.dist-info}/METADATA +4 -13
- {graphsense_python-2.18.0.dist-info → graphsense_python-2.19.0.dist-info}/RECORD +20 -23
- {graphsense_python-2.18.0.dist-info → graphsense_python-2.19.0.dist-info}/WHEEL +1 -1
- graphsense/api/entities_api.py +0 -2773
- graphsense/model/entity_addresses.py +0 -3
- graphsense/model/neighbor_entities.py +0 -3
- graphsense/models/entity_addresses.py +0 -96
- {graphsense_python-2.18.0.dist-info → graphsense_python-2.19.0.dist-info}/entry_points.txt +0 -0
- {graphsense_python-2.18.0.dist-info → graphsense_python-2.19.0.dist-info}/top_level.txt +0 -0
graphsense/__init__.py
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
__version__ = "2.
|
|
15
|
+
__version__ = "2.19.0"
|
|
16
16
|
|
|
17
17
|
# Define package exports
|
|
18
18
|
__all__ = [
|
|
@@ -20,7 +20,6 @@ __all__ = [
|
|
|
20
20
|
"BlocksApi",
|
|
21
21
|
"BulkApi",
|
|
22
22
|
"ClustersApi",
|
|
23
|
-
"EntitiesApi",
|
|
24
23
|
"GeneralApi",
|
|
25
24
|
"GraphApi",
|
|
26
25
|
"RatesApi",
|
|
@@ -59,7 +58,6 @@ __all__ = [
|
|
|
59
58
|
"CurrencyStats",
|
|
60
59
|
"DirectChangeHeuristic",
|
|
61
60
|
"Entity",
|
|
62
|
-
"EntityAddresses",
|
|
63
61
|
"ExternalConversion",
|
|
64
62
|
"GraphAddressNetworkSummary",
|
|
65
63
|
"GraphAddressOverall",
|
|
@@ -94,7 +92,6 @@ __all__ = [
|
|
|
94
92
|
"NeighborAddresses",
|
|
95
93
|
"NeighborCluster",
|
|
96
94
|
"NeighborClusters",
|
|
97
|
-
"NeighborEntities",
|
|
98
95
|
"NeighborEntity",
|
|
99
96
|
"NetworkCapabilities",
|
|
100
97
|
"OneTimeChangeHeuristic",
|
|
@@ -111,6 +108,7 @@ __all__ = [
|
|
|
111
108
|
"SearchResultLevel4",
|
|
112
109
|
"SearchResultLevel5",
|
|
113
110
|
"SearchResultLevel6",
|
|
111
|
+
"ServiceInfo",
|
|
114
112
|
"Stats",
|
|
115
113
|
"Tag",
|
|
116
114
|
"TagCloudEntry",
|
|
@@ -142,7 +140,6 @@ from graphsense.api.addresses_api import AddressesApi as AddressesApi
|
|
|
142
140
|
from graphsense.api.blocks_api import BlocksApi as BlocksApi
|
|
143
141
|
from graphsense.api.bulk_api import BulkApi as BulkApi
|
|
144
142
|
from graphsense.api.clusters_api import ClustersApi as ClustersApi
|
|
145
|
-
from graphsense.api.entities_api import EntitiesApi as EntitiesApi
|
|
146
143
|
from graphsense.api.general_api import GeneralApi as GeneralApi
|
|
147
144
|
from graphsense.api.graph_api import GraphApi as GraphApi
|
|
148
145
|
from graphsense.api.rates_api import RatesApi as RatesApi
|
|
@@ -185,7 +182,6 @@ from graphsense.models.consensus_entry import ConsensusEntry as ConsensusEntry
|
|
|
185
182
|
from graphsense.models.currency_stats import CurrencyStats as CurrencyStats
|
|
186
183
|
from graphsense.models.direct_change_heuristic import DirectChangeHeuristic as DirectChangeHeuristic
|
|
187
184
|
from graphsense.models.entity import Entity as Entity
|
|
188
|
-
from graphsense.models.entity_addresses import EntityAddresses as EntityAddresses
|
|
189
185
|
from graphsense.models.external_conversion import ExternalConversion as ExternalConversion
|
|
190
186
|
from graphsense.models.graph_address_network_summary import GraphAddressNetworkSummary as GraphAddressNetworkSummary
|
|
191
187
|
from graphsense.models.graph_address_overall import GraphAddressOverall as GraphAddressOverall
|
|
@@ -220,7 +216,6 @@ from graphsense.models.neighbor_address import NeighborAddress as NeighborAddres
|
|
|
220
216
|
from graphsense.models.neighbor_addresses import NeighborAddresses as NeighborAddresses
|
|
221
217
|
from graphsense.models.neighbor_cluster import NeighborCluster as NeighborCluster
|
|
222
218
|
from graphsense.models.neighbor_clusters import NeighborClusters as NeighborClusters
|
|
223
|
-
from graphsense.models.neighbor_entities import NeighborEntities as NeighborEntities
|
|
224
219
|
from graphsense.models.neighbor_entity import NeighborEntity as NeighborEntity
|
|
225
220
|
from graphsense.models.network_capabilities import NetworkCapabilities as NetworkCapabilities
|
|
226
221
|
from graphsense.models.one_time_change_heuristic import OneTimeChangeHeuristic as OneTimeChangeHeuristic
|
|
@@ -237,6 +232,7 @@ from graphsense.models.search_result_level3 import SearchResultLevel3 as SearchR
|
|
|
237
232
|
from graphsense.models.search_result_level4 import SearchResultLevel4 as SearchResultLevel4
|
|
238
233
|
from graphsense.models.search_result_level5 import SearchResultLevel5 as SearchResultLevel5
|
|
239
234
|
from graphsense.models.search_result_level6 import SearchResultLevel6 as SearchResultLevel6
|
|
235
|
+
from graphsense.models.service_info import ServiceInfo as ServiceInfo
|
|
240
236
|
from graphsense.models.stats import Stats as Stats
|
|
241
237
|
from graphsense.models.tag import Tag as Tag
|
|
242
238
|
from graphsense.models.tag_cloud_entry import TagCloudEntry as TagCloudEntry
|
|
@@ -259,3 +255,5 @@ from graphsense.models.wasabi_heuristic import WasabiHeuristic as WasabiHeuristi
|
|
|
259
255
|
from graphsense.models.whirlpool_coin_join_heuristic import WhirlpoolCoinJoinHeuristic as WhirlpoolCoinJoinHeuristic
|
|
260
256
|
from graphsense.models.whirlpool_tx0_heuristic import WhirlpoolTx0Heuristic as WhirlpoolTx0Heuristic
|
|
261
257
|
|
|
258
|
+
# Pointers for removed client names (hand-written)
|
|
259
|
+
import graphsense.removed # noqa: F401, E402
|
|
@@ -258,6 +258,83 @@ def _keccak256(data: bytes) -> bytes:
|
|
|
258
258
|
# btc/ltc/zec/trx copied verbatim from utils/address.py (pure already).
|
|
259
259
|
|
|
260
260
|
|
|
261
|
+
def base58_check_payload(s: str) -> "bytes | None":
|
|
262
|
+
"""The payload (version + body, without checksum) of a Base58Check
|
|
263
|
+
string, or None if it is not one."""
|
|
264
|
+
try:
|
|
265
|
+
decoded = base58_check_decode(s)
|
|
266
|
+
except ValueError:
|
|
267
|
+
return None
|
|
268
|
+
if len(decoded) < 5:
|
|
269
|
+
return None
|
|
270
|
+
payload, checksum = decoded[:-4], decoded[-4:]
|
|
271
|
+
if hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4] != checksum:
|
|
272
|
+
return None
|
|
273
|
+
return payload
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def base58_version_ok(s: str, versions: dict) -> bool:
|
|
277
|
+
"""True if ``s`` is Base58Check with one of ``versions`` (version bytes
|
|
278
|
+
-> allowed body lengths). A valid checksum alone says nothing: private
|
|
279
|
+
keys, extended keys and other chains' addresses have one too."""
|
|
280
|
+
payload = base58_check_payload(s)
|
|
281
|
+
if payload is None:
|
|
282
|
+
return False
|
|
283
|
+
for version, lengths in versions.items():
|
|
284
|
+
if payload.startswith(version) and len(payload) - len(version) in lengths:
|
|
285
|
+
return True
|
|
286
|
+
return False
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
_BECH32_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def bech32_data(s: str, expected_hrp: str) -> "tuple | None":
|
|
293
|
+
"""(checksum spec, 5-bit data without checksum) of a bech32/bech32m
|
|
294
|
+
string with ``expected_hrp``, else None. Unlike ``bech32_validate`` no
|
|
295
|
+
segwit rules and no 90-character limit (Zcash addresses are longer)."""
|
|
296
|
+
if s != s.lower() and s != s.upper():
|
|
297
|
+
return None
|
|
298
|
+
s = s.lower()
|
|
299
|
+
pos = s.rfind("1")
|
|
300
|
+
if pos < 1 or pos + 7 > len(s) or s[:pos] != expected_hrp:
|
|
301
|
+
return None
|
|
302
|
+
data_part = s[pos + 1 :]
|
|
303
|
+
if any(c not in _BECH32_CHARSET for c in data_part):
|
|
304
|
+
return None
|
|
305
|
+
data = [_BECH32_CHARSET.find(c) for c in data_part]
|
|
306
|
+
spec = bech32_checksum_spec(expected_hrp, data)
|
|
307
|
+
if spec is None:
|
|
308
|
+
return None
|
|
309
|
+
return spec, data[:-6]
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
# Base58Check version bytes -> length of the hash that follows.
|
|
313
|
+
_BTC_BASE58_VERSIONS = {
|
|
314
|
+
b"\x00": {20}, # P2PKH
|
|
315
|
+
b"\x05": {20}, # P2SH
|
|
316
|
+
b"\x6f": {20}, # testnet P2PKH
|
|
317
|
+
b"\xc4": {20}, # testnet P2SH
|
|
318
|
+
}
|
|
319
|
+
_LTC_BASE58_VERSIONS = {
|
|
320
|
+
b"\x30": {20}, # L, P2PKH
|
|
321
|
+
b"\x32": {20}, # M, P2SH
|
|
322
|
+
b"\x05": {20}, # 3, P2SH (old, shared with BTC)
|
|
323
|
+
b"\x6f": {20}, # testnet P2PKH
|
|
324
|
+
b"\xc4": {20}, # testnet P2SH (old)
|
|
325
|
+
b"\x3a": {20}, # testnet P2SH
|
|
326
|
+
}
|
|
327
|
+
_ZEC_BASE58_VERSIONS = {
|
|
328
|
+
b"\x1c\xb8": {20}, # t1, P2PKH
|
|
329
|
+
b"\x1c\xbd": {20}, # t3, P2SH
|
|
330
|
+
b"\x1d\x25": {20}, # tm, testnet P2PKH
|
|
331
|
+
b"\x1c\xba": {20}, # t2, testnet P2SH
|
|
332
|
+
b"\x16\x9a": {64}, # zc, Sprout
|
|
333
|
+
b"\x16\xb6": {64}, # zt, testnet Sprout
|
|
334
|
+
}
|
|
335
|
+
_TRX_BASE58_VERSIONS = {b"\x41": {20}}
|
|
336
|
+
|
|
337
|
+
|
|
261
338
|
def validate_btc_address(address: str) -> bool:
|
|
262
339
|
if not address:
|
|
263
340
|
return False
|
|
@@ -265,13 +342,7 @@ def validate_btc_address(address: str) -> bool:
|
|
|
265
342
|
return bech32_validate(address, "bc")
|
|
266
343
|
elif address.lower().startswith("tb1"):
|
|
267
344
|
return bech32_validate(address, "tb")
|
|
268
|
-
|
|
269
|
-
return base58_check_validate(address)
|
|
270
|
-
elif address[0] in "2mn":
|
|
271
|
-
return base58_check_validate(address)
|
|
272
|
-
elif address[0] in "59LKc":
|
|
273
|
-
return base58_check_validate(address)
|
|
274
|
-
return False
|
|
345
|
+
return base58_version_ok(address, _BTC_BASE58_VERSIONS)
|
|
275
346
|
|
|
276
347
|
|
|
277
348
|
def validate_ltc_address(address: str) -> bool:
|
|
@@ -279,27 +350,25 @@ def validate_ltc_address(address: str) -> bool:
|
|
|
279
350
|
return False
|
|
280
351
|
if address.lower().startswith("ltc1"):
|
|
281
352
|
return bech32_validate(address, "ltc")
|
|
282
|
-
|
|
283
|
-
return base58_check_validate(address)
|
|
284
|
-
elif address[0] in "2mn":
|
|
285
|
-
return base58_check_validate(address)
|
|
286
|
-
return False
|
|
353
|
+
return base58_version_ok(address, _LTC_BASE58_VERSIONS)
|
|
287
354
|
|
|
288
355
|
|
|
289
356
|
def validate_zec_address(address: str) -> bool:
|
|
290
357
|
if not address:
|
|
291
358
|
return False
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
359
|
+
lowered = address.lower()
|
|
360
|
+
for hrp in ("zs", "ztestsapling"):
|
|
361
|
+
if lowered.startswith(hrp + "1"):
|
|
362
|
+
decoded = bech32_data(address, hrp)
|
|
363
|
+
if decoded is None or decoded[0] != "bech32":
|
|
364
|
+
return False
|
|
365
|
+
body = bech32_convertbits(decoded[1], 5, 8, False)
|
|
366
|
+
return body is not None and len(body) == 43
|
|
367
|
+
for hrp in ("u", "utest"):
|
|
368
|
+
if lowered.startswith(hrp + "1"):
|
|
369
|
+
decoded = bech32_data(address, hrp)
|
|
370
|
+
return decoded is not None and decoded[0] == "bech32m"
|
|
371
|
+
return base58_version_ok(address, _ZEC_BASE58_VERSIONS)
|
|
303
372
|
|
|
304
373
|
|
|
305
374
|
def validate_trx_address(address: str) -> bool:
|
|
@@ -307,7 +376,7 @@ def validate_trx_address(address: str) -> bool:
|
|
|
307
376
|
return False
|
|
308
377
|
if not address.startswith("T") or len(address) != 34:
|
|
309
378
|
return False
|
|
310
|
-
return
|
|
379
|
+
return base58_version_ok(address, _TRX_BASE58_VERSIONS)
|
|
311
380
|
|
|
312
381
|
|
|
313
382
|
def validate_eth_address(address: str) -> bool:
|
graphsense/api/__init__.py
CHANGED
|
@@ -5,7 +5,6 @@ from graphsense.api.addresses_api import AddressesApi
|
|
|
5
5
|
from graphsense.api.blocks_api import BlocksApi
|
|
6
6
|
from graphsense.api.bulk_api import BulkApi
|
|
7
7
|
from graphsense.api.clusters_api import ClustersApi
|
|
8
|
-
from graphsense.api.entities_api import EntitiesApi
|
|
9
8
|
from graphsense.api.general_api import GeneralApi
|
|
10
9
|
from graphsense.api.graph_api import GraphApi
|
|
11
10
|
from graphsense.api.rates_api import RatesApi
|
graphsense/api/addresses_api.py
CHANGED
|
@@ -21,7 +21,6 @@ from graphsense.models.address import Address
|
|
|
21
21
|
from graphsense.models.address_tags import AddressTags
|
|
22
22
|
from graphsense.models.address_txs import AddressTxs
|
|
23
23
|
from graphsense.models.cluster import Cluster
|
|
24
|
-
from graphsense.models.entity import Entity
|
|
25
24
|
from graphsense.models.links import Links
|
|
26
25
|
from graphsense.models.neighbor_addresses import NeighborAddresses
|
|
27
26
|
from graphsense.models.related_addresses import RelatedAddresses
|
|
@@ -733,308 +732,6 @@ class AddressesApi:
|
|
|
733
732
|
|
|
734
733
|
|
|
735
734
|
|
|
736
|
-
@validate_call_compat
|
|
737
|
-
def get_address_entity(
|
|
738
|
-
self,
|
|
739
|
-
currency: Annotated[StrictStr, Field(description="The cryptocurrency code (e.g., btc)")],
|
|
740
|
-
address: Annotated[StrictStr, Field(description="The cryptocurrency address")],
|
|
741
|
-
include_actors: Annotated[Optional[StrictBool], Field(description="Whether to include actor information")] = None,
|
|
742
|
-
_request_timeout: Union[
|
|
743
|
-
None,
|
|
744
|
-
Annotated[StrictFloat, Field(gt=0)],
|
|
745
|
-
Tuple[
|
|
746
|
-
Annotated[StrictFloat, Field(gt=0)],
|
|
747
|
-
Annotated[StrictFloat, Field(gt=0)]
|
|
748
|
-
]
|
|
749
|
-
] = None,
|
|
750
|
-
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
|
751
|
-
_content_type: Optional[StrictStr] = None,
|
|
752
|
-
_headers: Optional[Dict[StrictStr, Any]] = None,
|
|
753
|
-
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
|
754
|
-
) -> Entity:
|
|
755
|
-
"""(Deprecated) Get the entity for an address
|
|
756
|
-
|
|
757
|
-
Deprecated alias for `GET /{currency}/addresses/{address}/cluster`. Returns the address cluster that contains the given address.
|
|
758
|
-
|
|
759
|
-
:param currency: The cryptocurrency code (e.g., btc) (required)
|
|
760
|
-
:type currency: str
|
|
761
|
-
:param address: The cryptocurrency address (required)
|
|
762
|
-
:type address: str
|
|
763
|
-
:param include_actors: Whether to include actor information
|
|
764
|
-
:type include_actors: bool
|
|
765
|
-
:param _request_timeout: timeout setting for this request. If one
|
|
766
|
-
number provided, it will be total request
|
|
767
|
-
timeout. It can also be a pair (tuple) of
|
|
768
|
-
(connection, read) timeouts.
|
|
769
|
-
:type _request_timeout: int, tuple(int, int), optional
|
|
770
|
-
:param _request_auth: set to override the auth_settings for an a single
|
|
771
|
-
request; this effectively ignores the
|
|
772
|
-
authentication in the spec for a single request.
|
|
773
|
-
:type _request_auth: dict, optional
|
|
774
|
-
:param _content_type: force content-type for the request.
|
|
775
|
-
:type _content_type: str, Optional
|
|
776
|
-
:param _headers: set to override the headers for a single
|
|
777
|
-
request; this effectively ignores the headers
|
|
778
|
-
in the spec for a single request.
|
|
779
|
-
:type _headers: dict, optional
|
|
780
|
-
:param _host_index: set to override the host_index for a single
|
|
781
|
-
request; this effectively ignores the host_index
|
|
782
|
-
in the spec for a single request.
|
|
783
|
-
:type _host_index: int, optional
|
|
784
|
-
:return: Returns the result object.
|
|
785
|
-
""" # noqa: E501
|
|
786
|
-
warnings.warn("GET /{currency}/addresses/{address}/entity is deprecated.", DeprecationWarning)
|
|
787
|
-
|
|
788
|
-
_param = self._get_address_entity_serialize(
|
|
789
|
-
currency=currency,
|
|
790
|
-
address=address,
|
|
791
|
-
include_actors=include_actors,
|
|
792
|
-
_request_auth=_request_auth,
|
|
793
|
-
_content_type=_content_type,
|
|
794
|
-
_headers=_headers,
|
|
795
|
-
_host_index=_host_index
|
|
796
|
-
)
|
|
797
|
-
|
|
798
|
-
_response_types_map: Dict[str, Optional[str]] = {
|
|
799
|
-
'200': "Entity",
|
|
800
|
-
'404': None,
|
|
801
|
-
'422': "HTTPValidationError",
|
|
802
|
-
}
|
|
803
|
-
response_data = self.api_client.call_api(
|
|
804
|
-
*_param,
|
|
805
|
-
_request_timeout=_request_timeout
|
|
806
|
-
)
|
|
807
|
-
response_data.read()
|
|
808
|
-
return self.api_client.response_deserialize(
|
|
809
|
-
response_data=response_data,
|
|
810
|
-
response_types_map=_response_types_map,
|
|
811
|
-
).data
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
@validate_call_compat
|
|
815
|
-
def get_address_entity_with_http_info(
|
|
816
|
-
self,
|
|
817
|
-
currency: Annotated[StrictStr, Field(description="The cryptocurrency code (e.g., btc)")],
|
|
818
|
-
address: Annotated[StrictStr, Field(description="The cryptocurrency address")],
|
|
819
|
-
include_actors: Annotated[Optional[StrictBool], Field(description="Whether to include actor information")] = None,
|
|
820
|
-
_request_timeout: Union[
|
|
821
|
-
None,
|
|
822
|
-
Annotated[StrictFloat, Field(gt=0)],
|
|
823
|
-
Tuple[
|
|
824
|
-
Annotated[StrictFloat, Field(gt=0)],
|
|
825
|
-
Annotated[StrictFloat, Field(gt=0)]
|
|
826
|
-
]
|
|
827
|
-
] = None,
|
|
828
|
-
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
|
829
|
-
_content_type: Optional[StrictStr] = None,
|
|
830
|
-
_headers: Optional[Dict[StrictStr, Any]] = None,
|
|
831
|
-
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
|
832
|
-
) -> ApiResponse[Entity]:
|
|
833
|
-
"""(Deprecated) Get the entity for an address
|
|
834
|
-
|
|
835
|
-
Deprecated alias for `GET /{currency}/addresses/{address}/cluster`. Returns the address cluster that contains the given address.
|
|
836
|
-
|
|
837
|
-
:param currency: The cryptocurrency code (e.g., btc) (required)
|
|
838
|
-
:type currency: str
|
|
839
|
-
:param address: The cryptocurrency address (required)
|
|
840
|
-
:type address: str
|
|
841
|
-
:param include_actors: Whether to include actor information
|
|
842
|
-
:type include_actors: bool
|
|
843
|
-
:param _request_timeout: timeout setting for this request. If one
|
|
844
|
-
number provided, it will be total request
|
|
845
|
-
timeout. It can also be a pair (tuple) of
|
|
846
|
-
(connection, read) timeouts.
|
|
847
|
-
:type _request_timeout: int, tuple(int, int), optional
|
|
848
|
-
:param _request_auth: set to override the auth_settings for an a single
|
|
849
|
-
request; this effectively ignores the
|
|
850
|
-
authentication in the spec for a single request.
|
|
851
|
-
:type _request_auth: dict, optional
|
|
852
|
-
:param _content_type: force content-type for the request.
|
|
853
|
-
:type _content_type: str, Optional
|
|
854
|
-
:param _headers: set to override the headers for a single
|
|
855
|
-
request; this effectively ignores the headers
|
|
856
|
-
in the spec for a single request.
|
|
857
|
-
:type _headers: dict, optional
|
|
858
|
-
:param _host_index: set to override the host_index for a single
|
|
859
|
-
request; this effectively ignores the host_index
|
|
860
|
-
in the spec for a single request.
|
|
861
|
-
:type _host_index: int, optional
|
|
862
|
-
:return: Returns the result object.
|
|
863
|
-
""" # noqa: E501
|
|
864
|
-
warnings.warn("GET /{currency}/addresses/{address}/entity is deprecated.", DeprecationWarning)
|
|
865
|
-
|
|
866
|
-
_param = self._get_address_entity_serialize(
|
|
867
|
-
currency=currency,
|
|
868
|
-
address=address,
|
|
869
|
-
include_actors=include_actors,
|
|
870
|
-
_request_auth=_request_auth,
|
|
871
|
-
_content_type=_content_type,
|
|
872
|
-
_headers=_headers,
|
|
873
|
-
_host_index=_host_index
|
|
874
|
-
)
|
|
875
|
-
|
|
876
|
-
_response_types_map: Dict[str, Optional[str]] = {
|
|
877
|
-
'200': "Entity",
|
|
878
|
-
'404': None,
|
|
879
|
-
'422': "HTTPValidationError",
|
|
880
|
-
}
|
|
881
|
-
response_data = self.api_client.call_api(
|
|
882
|
-
*_param,
|
|
883
|
-
_request_timeout=_request_timeout
|
|
884
|
-
)
|
|
885
|
-
response_data.read()
|
|
886
|
-
return self.api_client.response_deserialize(
|
|
887
|
-
response_data=response_data,
|
|
888
|
-
response_types_map=_response_types_map,
|
|
889
|
-
)
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
@validate_call_compat
|
|
893
|
-
def get_address_entity_without_preload_content(
|
|
894
|
-
self,
|
|
895
|
-
currency: Annotated[StrictStr, Field(description="The cryptocurrency code (e.g., btc)")],
|
|
896
|
-
address: Annotated[StrictStr, Field(description="The cryptocurrency address")],
|
|
897
|
-
include_actors: Annotated[Optional[StrictBool], Field(description="Whether to include actor information")] = None,
|
|
898
|
-
_request_timeout: Union[
|
|
899
|
-
None,
|
|
900
|
-
Annotated[StrictFloat, Field(gt=0)],
|
|
901
|
-
Tuple[
|
|
902
|
-
Annotated[StrictFloat, Field(gt=0)],
|
|
903
|
-
Annotated[StrictFloat, Field(gt=0)]
|
|
904
|
-
]
|
|
905
|
-
] = None,
|
|
906
|
-
_request_auth: Optional[Dict[StrictStr, Any]] = None,
|
|
907
|
-
_content_type: Optional[StrictStr] = None,
|
|
908
|
-
_headers: Optional[Dict[StrictStr, Any]] = None,
|
|
909
|
-
_host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0,
|
|
910
|
-
) -> RESTResponseType:
|
|
911
|
-
"""(Deprecated) Get the entity for an address
|
|
912
|
-
|
|
913
|
-
Deprecated alias for `GET /{currency}/addresses/{address}/cluster`. Returns the address cluster that contains the given address.
|
|
914
|
-
|
|
915
|
-
:param currency: The cryptocurrency code (e.g., btc) (required)
|
|
916
|
-
:type currency: str
|
|
917
|
-
:param address: The cryptocurrency address (required)
|
|
918
|
-
:type address: str
|
|
919
|
-
:param include_actors: Whether to include actor information
|
|
920
|
-
:type include_actors: bool
|
|
921
|
-
:param _request_timeout: timeout setting for this request. If one
|
|
922
|
-
number provided, it will be total request
|
|
923
|
-
timeout. It can also be a pair (tuple) of
|
|
924
|
-
(connection, read) timeouts.
|
|
925
|
-
:type _request_timeout: int, tuple(int, int), optional
|
|
926
|
-
:param _request_auth: set to override the auth_settings for an a single
|
|
927
|
-
request; this effectively ignores the
|
|
928
|
-
authentication in the spec for a single request.
|
|
929
|
-
:type _request_auth: dict, optional
|
|
930
|
-
:param _content_type: force content-type for the request.
|
|
931
|
-
:type _content_type: str, Optional
|
|
932
|
-
:param _headers: set to override the headers for a single
|
|
933
|
-
request; this effectively ignores the headers
|
|
934
|
-
in the spec for a single request.
|
|
935
|
-
:type _headers: dict, optional
|
|
936
|
-
:param _host_index: set to override the host_index for a single
|
|
937
|
-
request; this effectively ignores the host_index
|
|
938
|
-
in the spec for a single request.
|
|
939
|
-
:type _host_index: int, optional
|
|
940
|
-
:return: Returns the result object.
|
|
941
|
-
""" # noqa: E501
|
|
942
|
-
warnings.warn("GET /{currency}/addresses/{address}/entity is deprecated.", DeprecationWarning)
|
|
943
|
-
|
|
944
|
-
_param = self._get_address_entity_serialize(
|
|
945
|
-
currency=currency,
|
|
946
|
-
address=address,
|
|
947
|
-
include_actors=include_actors,
|
|
948
|
-
_request_auth=_request_auth,
|
|
949
|
-
_content_type=_content_type,
|
|
950
|
-
_headers=_headers,
|
|
951
|
-
_host_index=_host_index
|
|
952
|
-
)
|
|
953
|
-
|
|
954
|
-
_response_types_map: Dict[str, Optional[str]] = {
|
|
955
|
-
'200': "Entity",
|
|
956
|
-
'404': None,
|
|
957
|
-
'422': "HTTPValidationError",
|
|
958
|
-
}
|
|
959
|
-
response_data = self.api_client.call_api(
|
|
960
|
-
*_param,
|
|
961
|
-
_request_timeout=_request_timeout
|
|
962
|
-
)
|
|
963
|
-
return response_data.response
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
def _get_address_entity_serialize(
|
|
967
|
-
self,
|
|
968
|
-
currency,
|
|
969
|
-
address,
|
|
970
|
-
include_actors,
|
|
971
|
-
_request_auth,
|
|
972
|
-
_content_type,
|
|
973
|
-
_headers,
|
|
974
|
-
_host_index,
|
|
975
|
-
) -> RequestSerialized:
|
|
976
|
-
|
|
977
|
-
_host = None
|
|
978
|
-
|
|
979
|
-
_collection_formats: Dict[str, str] = {
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
_path_params: Dict[str, str] = {}
|
|
983
|
-
_query_params: List[Tuple[str, str]] = []
|
|
984
|
-
_header_params: Dict[str, Optional[str]] = _headers or {}
|
|
985
|
-
_form_params: List[Tuple[str, str]] = []
|
|
986
|
-
_files: Dict[
|
|
987
|
-
str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]]
|
|
988
|
-
] = {}
|
|
989
|
-
_body_params: Optional[bytes] = None
|
|
990
|
-
|
|
991
|
-
# process the path parameters
|
|
992
|
-
if currency is not None:
|
|
993
|
-
_path_params['currency'] = currency
|
|
994
|
-
if address is not None:
|
|
995
|
-
_path_params['address'] = address
|
|
996
|
-
# process the query parameters
|
|
997
|
-
if include_actors is not None:
|
|
998
|
-
|
|
999
|
-
_query_params.append(('include_actors', include_actors))
|
|
1000
|
-
|
|
1001
|
-
# process the header parameters
|
|
1002
|
-
# process the form parameters
|
|
1003
|
-
# process the body parameter
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
# set the HTTP header `Accept`
|
|
1007
|
-
if 'Accept' not in _header_params:
|
|
1008
|
-
_header_params['Accept'] = self.api_client.select_header_accept(
|
|
1009
|
-
[
|
|
1010
|
-
'application/json'
|
|
1011
|
-
]
|
|
1012
|
-
)
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
# authentication setting
|
|
1016
|
-
_auth_settings: List[str] = [
|
|
1017
|
-
'api_key'
|
|
1018
|
-
]
|
|
1019
|
-
|
|
1020
|
-
return self.api_client.param_serialize(
|
|
1021
|
-
method='GET',
|
|
1022
|
-
resource_path='/{currency}/addresses/{address}/entity',
|
|
1023
|
-
path_params=_path_params,
|
|
1024
|
-
query_params=_query_params,
|
|
1025
|
-
header_params=_header_params,
|
|
1026
|
-
body=_body_params,
|
|
1027
|
-
post_params=_form_params,
|
|
1028
|
-
files=_files,
|
|
1029
|
-
auth_settings=_auth_settings,
|
|
1030
|
-
collection_formats=_collection_formats,
|
|
1031
|
-
_host=_host,
|
|
1032
|
-
_request_auth=_request_auth
|
|
1033
|
-
)
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
735
|
@validate_call_compat
|
|
1039
736
|
def get_tag_summary_by_address(
|
|
1040
737
|
self,
|
graphsense/api/general_api.py
CHANGED
|
@@ -146,7 +146,7 @@ class GeneralApi:
|
|
|
146
146
|
) -> Capabilities:
|
|
147
147
|
"""Get per-network feature availability
|
|
148
148
|
|
|
149
|
-
Returns which optional feature families are disabled per served network. A network absent from the list is fully enabled, as is every network of a deployment that does not serve this endpoint (404).
|
|
149
|
+
Returns which optional feature families are disabled per served network. A network absent from the list is fully enabled, as is every network of a deployment that does not serve this endpoint (404). Also lists the optional services of the deployment (e.g. address notifications) with their versions.
|
|
150
150
|
|
|
151
151
|
:param _request_timeout: timeout setting for this request. If one
|
|
152
152
|
number provided, it will be total request
|
|
@@ -209,7 +209,7 @@ class GeneralApi:
|
|
|
209
209
|
) -> ApiResponse[Capabilities]:
|
|
210
210
|
"""Get per-network feature availability
|
|
211
211
|
|
|
212
|
-
Returns which optional feature families are disabled per served network. A network absent from the list is fully enabled, as is every network of a deployment that does not serve this endpoint (404).
|
|
212
|
+
Returns which optional feature families are disabled per served network. A network absent from the list is fully enabled, as is every network of a deployment that does not serve this endpoint (404). Also lists the optional services of the deployment (e.g. address notifications) with their versions.
|
|
213
213
|
|
|
214
214
|
:param _request_timeout: timeout setting for this request. If one
|
|
215
215
|
number provided, it will be total request
|
|
@@ -272,7 +272,7 @@ class GeneralApi:
|
|
|
272
272
|
) -> RESTResponseType:
|
|
273
273
|
"""Get per-network feature availability
|
|
274
274
|
|
|
275
|
-
Returns which optional feature families are disabled per served network. A network absent from the list is fully enabled, as is every network of a deployment that does not serve this endpoint (404).
|
|
275
|
+
Returns which optional feature families are disabled per served network. A network absent from the list is fully enabled, as is every network of a deployment that does not serve this endpoint (404). Also lists the optional services of the deployment (e.g. address notifications) with their versions.
|
|
276
276
|
|
|
277
277
|
:param _request_timeout: timeout setting for this request. If one
|
|
278
278
|
number provided, it will be total request
|
graphsense/api_client.py
CHANGED
|
@@ -95,7 +95,7 @@ class ApiClient:
|
|
|
95
95
|
self.default_headers[header_name] = header_value
|
|
96
96
|
self.cookie = cookie
|
|
97
97
|
# Set default User-Agent.
|
|
98
|
-
self.user_agent = 'graphsense-python/2.
|
|
98
|
+
self.user_agent = 'graphsense-python/2.19.0'
|
|
99
99
|
self.client_side_validation = configuration.client_side_validation
|
|
100
100
|
|
|
101
101
|
def __enter__(self):
|
graphsense/cli/raw.py
CHANGED
|
@@ -18,10 +18,11 @@ import rich_click as click
|
|
|
18
18
|
import graphsense
|
|
19
19
|
from graphsense.cli.context import CliContext
|
|
20
20
|
from graphsense.ext import output as out_mod
|
|
21
|
+
from graphsense.removed import REMOVED_NAMES
|
|
21
22
|
|
|
22
23
|
pass_ctx = click.make_pass_decorator(CliContext)
|
|
23
24
|
|
|
24
|
-
_DEPRECATED_APIS =
|
|
25
|
+
_DEPRECATED_APIS: set[str] = set()
|
|
25
26
|
_INTERNAL_SUFFIXES = ("_with_http_info", "_without_preload_content")
|
|
26
27
|
_PRIVATE_PREFIXES = ("_",)
|
|
27
28
|
|
|
@@ -49,9 +50,28 @@ def build_raw_group() -> click.Group:
|
|
|
49
50
|
subgroup = _make_api_subgroup(cls_name, cls)
|
|
50
51
|
raw_group.add_command(subgroup)
|
|
51
52
|
|
|
53
|
+
for cls_name, message in REMOVED_NAMES.items():
|
|
54
|
+
if cls_name.endswith("Api"):
|
|
55
|
+
raw_group.add_command(_make_removed_group(cls_name, message))
|
|
56
|
+
|
|
52
57
|
return raw_group
|
|
53
58
|
|
|
54
59
|
|
|
60
|
+
def _make_removed_group(cls_name: str, message: str) -> click.Command:
|
|
61
|
+
"""Hidden stand-in for a removed API group: fails with what replaces it."""
|
|
62
|
+
|
|
63
|
+
@click.command(
|
|
64
|
+
name=cls_name[: -len("Api")].lower(),
|
|
65
|
+
hidden=True,
|
|
66
|
+
context_settings={"ignore_unknown_options": True, "allow_extra_args": True},
|
|
67
|
+
add_help_option=False,
|
|
68
|
+
)
|
|
69
|
+
def removed() -> None:
|
|
70
|
+
raise click.UsageError(message)
|
|
71
|
+
|
|
72
|
+
return removed
|
|
73
|
+
|
|
74
|
+
|
|
55
75
|
def _iter_api_class_names() -> t.Iterator[str]:
|
|
56
76
|
for name in dir(graphsense):
|
|
57
77
|
if name.endswith("Api") and inspect.isclass(getattr(graphsense, name)):
|
graphsense/configuration.py
CHANGED
|
@@ -533,8 +533,8 @@ conf = graphsense.Configuration(
|
|
|
533
533
|
return "Python SDK Debug Report:\n"\
|
|
534
534
|
"OS: {env}\n"\
|
|
535
535
|
"Python Version: {pyversion}\n"\
|
|
536
|
-
"Version of the API: 2.
|
|
537
|
-
"SDK Package Version: 2.
|
|
536
|
+
"Version of the API: 2.19.0\n"\
|
|
537
|
+
"SDK Package Version: 2.19.0".\
|
|
538
538
|
format(env=sys.platform, pyversion=sys.version)
|
|
539
539
|
|
|
540
540
|
def get_host_settings(self) -> List[HostSetting]:
|