constellation-metagraph-sdk 0.1.0__tar.gz
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.
- constellation_metagraph_sdk-0.1.0/CHANGELOG.md +17 -0
- constellation_metagraph_sdk-0.1.0/PKG-INFO +531 -0
- constellation_metagraph_sdk-0.1.0/README.md +496 -0
- constellation_metagraph_sdk-0.1.0/pyproject.toml +93 -0
- constellation_metagraph_sdk-0.1.0/setup.cfg +4 -0
- constellation_metagraph_sdk-0.1.0/setup.py +5 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_metagraph_sdk.egg-info/PKG-INFO +531 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_metagraph_sdk.egg-info/SOURCES.txt +33 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_metagraph_sdk.egg-info/dependency_links.txt +1 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_metagraph_sdk.egg-info/requires.txt +11 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_metagraph_sdk.egg-info/top_level.txt +1 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/__init__.py +167 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/binary.py +66 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/canonicalize.py +47 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/codec.py +61 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/currency_transaction.py +546 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/currency_types.py +77 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/hash.py +80 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/network/__init__.py +62 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/network/client.py +95 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/network/metagraph_client.py +399 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/network/types.py +84 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/sign.py +117 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/signed_object.py +101 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/types.py +81 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/verify.py +124 -0
- constellation_metagraph_sdk-0.1.0/src/constellation_sdk/wallet.py +205 -0
- constellation_metagraph_sdk-0.1.0/tests/test_binary.py +85 -0
- constellation_metagraph_sdk-0.1.0/tests/test_canonicalize.py +69 -0
- constellation_metagraph_sdk-0.1.0/tests/test_cross_language.py +120 -0
- constellation_metagraph_sdk-0.1.0/tests/test_currency_transaction.py +290 -0
- constellation_metagraph_sdk-0.1.0/tests/test_currency_transaction_vectors.py +266 -0
- constellation_metagraph_sdk-0.1.0/tests/test_hash.py +73 -0
- constellation_metagraph_sdk-0.1.0/tests/test_integration.py +189 -0
- constellation_metagraph_sdk-0.1.0/tests/test_network.py +120 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the Python SDK will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2025-05-01
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Initial release
|
|
12
|
+
- Data transaction signing and verification (standard and DataUpdate modes)
|
|
13
|
+
- Currency transaction creation, signing, and verification (v2 format)
|
|
14
|
+
- Multi-signature support via `add_signature` and `batch_sign`
|
|
15
|
+
- Wallet utilities: key generation, address derivation, key validation
|
|
16
|
+
- Network clients: `CurrencyL1Client` and `DataL1Client`
|
|
17
|
+
- Cross-language compatibility with TypeScript, Rust, Go, and Java SDKs
|
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: constellation-metagraph-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for signing data transactions on Constellation data metagraphs built with metakit
|
|
5
|
+
Author-email: Constellation Network <contact@constellationnetwork.io>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/Constellation-Labs/metakit-sdk
|
|
8
|
+
Project-URL: Documentation, https://github.com/Constellation-Labs/metakit-sdk/tree/main/packages/python
|
|
9
|
+
Project-URL: Repository, https://github.com/Constellation-Labs/metakit-sdk.git
|
|
10
|
+
Project-URL: Issues, https://github.com/Constellation-Labs/metakit-sdk/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/Constellation-Labs/metakit-sdk/blob/main/packages/python/CHANGELOG.md
|
|
12
|
+
Keywords: constellation,metagraph,dag,ecdsa,secp256k1,signature,blockchain,rfc8785,canonicalize
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Security :: Cryptography
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
Requires-Dist: ecdsa>=0.19.0
|
|
26
|
+
Requires-Dist: rfc8785>=0.1.3
|
|
27
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: isort>=5.12.0; extra == "dev"
|
|
33
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
35
|
+
|
|
36
|
+
# Constellation Metagraph SDK - Python
|
|
37
|
+
|
|
38
|
+
Python SDK for signing data and currency transactions on Constellation Network metagraphs built with the [metakit](https://github.com/Constellation-Labs/metakit) framework.
|
|
39
|
+
|
|
40
|
+
> **Scope:** This SDK supports both data transactions (state updates) and metagraph token transactions (value transfers). It implements the standardized serialization, hashing, and signing routines defined by metakit and may not be compatible with metagraphs using custom serialization.
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install constellation-metagraph-sdk
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from constellation_sdk import (
|
|
52
|
+
create_signed_object,
|
|
53
|
+
verify,
|
|
54
|
+
generate_key_pair,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Generate a key pair
|
|
58
|
+
key_pair = generate_key_pair()
|
|
59
|
+
print(f'Address: {key_pair.address}')
|
|
60
|
+
|
|
61
|
+
# Sign data
|
|
62
|
+
data = {'action': 'UPDATE', 'payload': {'key': 'value'}}
|
|
63
|
+
signed = create_signed_object(data, key_pair.private_key)
|
|
64
|
+
|
|
65
|
+
# Verify
|
|
66
|
+
result = verify(signed)
|
|
67
|
+
print(f'Valid: {result.is_valid}')
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## API Reference
|
|
71
|
+
|
|
72
|
+
### High-Level API
|
|
73
|
+
|
|
74
|
+
#### `create_signed_object(value, private_key, is_data_update=False)`
|
|
75
|
+
|
|
76
|
+
Create a signed object with a single signature.
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
signed = create_signed_object(
|
|
80
|
+
{'action': 'test'},
|
|
81
|
+
private_key,
|
|
82
|
+
is_data_update=True # For L1 submission
|
|
83
|
+
)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
#### `add_signature(signed, private_key, is_data_update=False)`
|
|
87
|
+
|
|
88
|
+
Add an additional signature to an existing signed object.
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
signed = create_signed_object(data, party1_key)
|
|
92
|
+
signed = add_signature(signed, party2_key)
|
|
93
|
+
# len(signed.proofs) == 2
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### `batch_sign(value, private_keys, is_data_update=False)`
|
|
97
|
+
|
|
98
|
+
Create a signed object with multiple signatures at once.
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
signed = batch_sign(data, [key1, key2, key3])
|
|
102
|
+
# len(signed.proofs) == 3
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### `verify(signed, is_data_update=False)`
|
|
106
|
+
|
|
107
|
+
Verify all signatures on a signed object.
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
result = verify(signed)
|
|
111
|
+
if result.is_valid:
|
|
112
|
+
print('All signatures valid')
|
|
113
|
+
else:
|
|
114
|
+
print(f'Invalid proofs: {result.invalid_proofs}')
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Low-Level Primitives
|
|
118
|
+
|
|
119
|
+
#### `canonicalize(data)`
|
|
120
|
+
|
|
121
|
+
Canonicalize JSON data according to RFC 8785.
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
canonical = canonicalize({'b': 2, 'a': 1})
|
|
125
|
+
# '{"a":1,"b":2}'
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### `to_bytes(data, is_data_update=False)`
|
|
129
|
+
|
|
130
|
+
Convert data to binary bytes for signing.
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
# Regular encoding
|
|
134
|
+
bytes_data = to_bytes(data)
|
|
135
|
+
|
|
136
|
+
# DataUpdate encoding (with Constellation prefix)
|
|
137
|
+
update_bytes = to_bytes(data, is_data_update=True)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
#### `hash_data(data)` / `hash_bytes(data)`
|
|
141
|
+
|
|
142
|
+
Compute SHA-256 hash.
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
hash_result = hash_data(data)
|
|
146
|
+
print(hash_result.value) # 64-char hex
|
|
147
|
+
print(hash_result.bytes) # bytes
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### `sign(data, private_key)` / `sign_data_update(data, private_key)`
|
|
151
|
+
|
|
152
|
+
Sign data and return a proof.
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
proof = sign(data, private_key)
|
|
156
|
+
# SignatureProof(id='...', signature='...')
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### `sign_hash(hash_hex, private_key)`
|
|
160
|
+
|
|
161
|
+
Sign a pre-computed hash.
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
hash_result = hash_data(data)
|
|
165
|
+
signature = sign_hash(hash_result.value, private_key)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Wallet Utilities
|
|
169
|
+
|
|
170
|
+
#### `generate_key_pair()`
|
|
171
|
+
|
|
172
|
+
Generate a new random key pair.
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
key_pair = generate_key_pair()
|
|
176
|
+
# KeyPair(private_key, public_key, address)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### `key_pair_from_private_key(private_key)`
|
|
180
|
+
|
|
181
|
+
Derive a key pair from an existing private key.
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
key_pair = key_pair_from_private_key(existing_private_key)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### `get_public_key_id(private_key)`
|
|
188
|
+
|
|
189
|
+
Get the public key ID (128 chars, no 04 prefix) for use in proofs.
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
id = get_public_key_id(private_key)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Currency Transactions
|
|
196
|
+
|
|
197
|
+
#### `create_currency_transaction(params, private_key, last_ref)`
|
|
198
|
+
|
|
199
|
+
Create a metagraph token transaction.
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
from constellation_sdk.currency_transaction import create_currency_transaction
|
|
203
|
+
from constellation_sdk.currency_types import TransferParams, TransactionReference
|
|
204
|
+
|
|
205
|
+
tx = create_currency_transaction(
|
|
206
|
+
TransferParams(
|
|
207
|
+
destination='DAG88C9WDSKH5CYZTCEOZD...',
|
|
208
|
+
amount=100.5, # Tokens
|
|
209
|
+
fee=0,
|
|
210
|
+
),
|
|
211
|
+
private_key,
|
|
212
|
+
TransactionReference(hash='parent_hash...', ordinal=5)
|
|
213
|
+
)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### `verify_currency_transaction(transaction)`
|
|
217
|
+
|
|
218
|
+
Verify all signatures on a currency transaction.
|
|
219
|
+
|
|
220
|
+
```python
|
|
221
|
+
from constellation_sdk.currency_transaction import verify_currency_transaction
|
|
222
|
+
|
|
223
|
+
result = verify_currency_transaction(tx)
|
|
224
|
+
print(f'Valid: {result.is_valid}')
|
|
225
|
+
print(f'Valid proofs: {len(result.valid_proofs)}')
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### `sign_currency_transaction(transaction, private_key)`
|
|
229
|
+
|
|
230
|
+
Add an additional signature to a currency transaction (multi-sig).
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
from constellation_sdk.currency_transaction import sign_currency_transaction
|
|
234
|
+
|
|
235
|
+
# Add second signature
|
|
236
|
+
tx_multi_sig = sign_currency_transaction(tx, private_key2)
|
|
237
|
+
# tx_multi_sig.proofs has 2 signatures now
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
#### `create_currency_transaction_batch(transfers, private_key, last_ref)`
|
|
241
|
+
|
|
242
|
+
Create multiple currency transactions in a batch.
|
|
243
|
+
|
|
244
|
+
```python
|
|
245
|
+
from constellation_sdk.currency_transaction import create_currency_transaction_batch
|
|
246
|
+
|
|
247
|
+
transactions = create_currency_transaction_batch(
|
|
248
|
+
[
|
|
249
|
+
TransferParams(destination='DAG...1', amount=10, fee=0),
|
|
250
|
+
TransferParams(destination='DAG...2', amount=20, fee=0),
|
|
251
|
+
],
|
|
252
|
+
private_key,
|
|
253
|
+
last_ref
|
|
254
|
+
)
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
#### `hash_currency_transaction(transaction)`
|
|
258
|
+
|
|
259
|
+
Hash a currency transaction.
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
from constellation_sdk.currency_transaction import hash_currency_transaction
|
|
263
|
+
|
|
264
|
+
hash_result = hash_currency_transaction(tx)
|
|
265
|
+
print(f'Hash: {hash_result.value}')
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
#### `is_valid_dag_address(address)`
|
|
269
|
+
|
|
270
|
+
Validate a DAG address format.
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
from constellation_sdk.currency_transaction import is_valid_dag_address
|
|
274
|
+
|
|
275
|
+
if is_valid_dag_address('DAG88C9WDSKH5CYZTCEOZD...'):
|
|
276
|
+
print('Valid address')
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
#### `token_to_units(amount)` / `units_to_token(units)`
|
|
280
|
+
|
|
281
|
+
Convert between token amounts and smallest units (1e-8).
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
from constellation_sdk.currency_transaction import token_to_units, units_to_token
|
|
285
|
+
|
|
286
|
+
units = token_to_units(100.5) # 10050000000
|
|
287
|
+
tokens = units_to_token(10050000000) # 100.5
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Network Operations
|
|
291
|
+
|
|
292
|
+
#### `CurrencyL1Client`
|
|
293
|
+
|
|
294
|
+
Client for interacting with Currency L1 nodes.
|
|
295
|
+
|
|
296
|
+
```python
|
|
297
|
+
from constellation_sdk import CurrencyL1Client, NetworkConfig
|
|
298
|
+
|
|
299
|
+
config = NetworkConfig(
|
|
300
|
+
l1_url='http://localhost:9010',
|
|
301
|
+
timeout=30.0, # optional, defaults to 30s
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
client = CurrencyL1Client(config)
|
|
305
|
+
|
|
306
|
+
# Get last transaction reference for an address
|
|
307
|
+
last_ref = client.get_last_reference('DAG...')
|
|
308
|
+
|
|
309
|
+
# Submit a signed transaction
|
|
310
|
+
result = client.post_transaction(signed_tx)
|
|
311
|
+
print(f'Transaction hash: {result.hash}')
|
|
312
|
+
|
|
313
|
+
# Check pending transaction status
|
|
314
|
+
pending = client.get_pending_transaction(result.hash)
|
|
315
|
+
if pending:
|
|
316
|
+
print(f'Status: {pending.status}') # 'Waiting' | 'InProgress' | 'Accepted'
|
|
317
|
+
|
|
318
|
+
# Check node health
|
|
319
|
+
is_healthy = client.check_health()
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### `DataL1Client`
|
|
323
|
+
|
|
324
|
+
Client for interacting with Data L1 nodes (metagraphs).
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
from constellation_sdk import DataL1Client, NetworkConfig
|
|
328
|
+
|
|
329
|
+
config = NetworkConfig(data_l1_url='http://localhost:8080')
|
|
330
|
+
|
|
331
|
+
client = DataL1Client(config)
|
|
332
|
+
|
|
333
|
+
# Estimate fee for data submission
|
|
334
|
+
fee_info = client.estimate_fee(signed_data)
|
|
335
|
+
print(f'Fee: {fee_info.fee}, Address: {fee_info.address}')
|
|
336
|
+
|
|
337
|
+
# Submit signed data
|
|
338
|
+
result = client.post_data(signed_data)
|
|
339
|
+
print(f'Data hash: {result.hash}')
|
|
340
|
+
|
|
341
|
+
# Check node health
|
|
342
|
+
is_healthy = client.check_health()
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
#### Combined Configuration
|
|
346
|
+
|
|
347
|
+
```python
|
|
348
|
+
config = NetworkConfig(
|
|
349
|
+
l1_url='http://localhost:9010', # Currency L1
|
|
350
|
+
data_l1_url='http://localhost:8080', # Data L1
|
|
351
|
+
timeout=30.0,
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
l1_client = CurrencyL1Client(config)
|
|
355
|
+
data_client = DataL1Client(config)
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
#### Network Types
|
|
359
|
+
|
|
360
|
+
```python
|
|
361
|
+
@dataclass
|
|
362
|
+
class NetworkConfig:
|
|
363
|
+
l1_url: Optional[str] = None # Currency L1 endpoint
|
|
364
|
+
data_l1_url: Optional[str] = None # Data L1 endpoint
|
|
365
|
+
timeout: float = 30.0 # Request timeout in seconds
|
|
366
|
+
|
|
367
|
+
@dataclass
|
|
368
|
+
class PostTransactionResponse:
|
|
369
|
+
hash: str
|
|
370
|
+
|
|
371
|
+
@dataclass
|
|
372
|
+
class PendingTransaction:
|
|
373
|
+
hash: str
|
|
374
|
+
status: Literal["Waiting", "InProgress", "Accepted"]
|
|
375
|
+
transaction: CurrencyTransaction
|
|
376
|
+
|
|
377
|
+
@dataclass
|
|
378
|
+
class EstimateFeeResponse:
|
|
379
|
+
fee: int
|
|
380
|
+
address: str
|
|
381
|
+
|
|
382
|
+
@dataclass
|
|
383
|
+
class PostDataResponse:
|
|
384
|
+
hash: str
|
|
385
|
+
|
|
386
|
+
class NetworkError(Exception):
|
|
387
|
+
status_code: Optional[int]
|
|
388
|
+
response: Optional[str]
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
## Types
|
|
392
|
+
|
|
393
|
+
```python
|
|
394
|
+
from dataclasses import dataclass
|
|
395
|
+
from typing import List, TypeVar, Generic
|
|
396
|
+
|
|
397
|
+
@dataclass(frozen=True)
|
|
398
|
+
class SignatureProof:
|
|
399
|
+
id: str # Public key (128 chars)
|
|
400
|
+
signature: str # DER signature hex
|
|
401
|
+
|
|
402
|
+
@dataclass
|
|
403
|
+
class Signed(Generic[T]):
|
|
404
|
+
value: T
|
|
405
|
+
proofs: List[SignatureProof]
|
|
406
|
+
|
|
407
|
+
@dataclass(frozen=True)
|
|
408
|
+
class KeyPair:
|
|
409
|
+
private_key: str
|
|
410
|
+
public_key: str
|
|
411
|
+
address: str
|
|
412
|
+
|
|
413
|
+
@dataclass(frozen=True)
|
|
414
|
+
class Hash:
|
|
415
|
+
value: str # 64-char hex
|
|
416
|
+
bytes: bytes # 32 bytes
|
|
417
|
+
|
|
418
|
+
@dataclass
|
|
419
|
+
class VerificationResult:
|
|
420
|
+
is_valid: bool
|
|
421
|
+
valid_proofs: List[SignatureProof]
|
|
422
|
+
invalid_proofs: List[SignatureProof]
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
## Usage Examples
|
|
426
|
+
|
|
427
|
+
### Submit DataUpdate to L1
|
|
428
|
+
|
|
429
|
+
```python
|
|
430
|
+
from constellation_sdk import create_signed_object, DataL1Client, NetworkConfig
|
|
431
|
+
|
|
432
|
+
# Your metagraph data update
|
|
433
|
+
data_update = {
|
|
434
|
+
'action': 'TRANSFER',
|
|
435
|
+
'from': 'address1',
|
|
436
|
+
'to': 'address2',
|
|
437
|
+
'amount': 100
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
# Sign as DataUpdate
|
|
441
|
+
signed = create_signed_object(data_update, private_key, is_data_update=True)
|
|
442
|
+
|
|
443
|
+
# Submit to data-l1 using the client
|
|
444
|
+
client = DataL1Client(NetworkConfig(data_l1_url='http://l1-node:9300'))
|
|
445
|
+
result = client.post_data(signed)
|
|
446
|
+
print(f'Submitted with hash: {result.hash}')
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Multi-Signature Workflow
|
|
450
|
+
|
|
451
|
+
```python
|
|
452
|
+
from constellation_sdk import create_signed_object, add_signature, verify
|
|
453
|
+
|
|
454
|
+
# Party 1 creates and signs
|
|
455
|
+
signed = create_signed_object(data, party1_key)
|
|
456
|
+
|
|
457
|
+
# Party 2 adds signature
|
|
458
|
+
signed = add_signature(signed, party2_key)
|
|
459
|
+
|
|
460
|
+
# Party 3 adds signature
|
|
461
|
+
signed = add_signature(signed, party3_key)
|
|
462
|
+
|
|
463
|
+
# Verify all signatures
|
|
464
|
+
result = verify(signed)
|
|
465
|
+
print(f'{len(result.valid_proofs)} valid signatures')
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### Working with Raw Bytes
|
|
469
|
+
|
|
470
|
+
```python
|
|
471
|
+
from constellation_sdk import canonicalize, to_bytes, hash_bytes
|
|
472
|
+
|
|
473
|
+
# Get canonical JSON
|
|
474
|
+
canonical = canonicalize(data)
|
|
475
|
+
print(f'Canonical: {canonical}')
|
|
476
|
+
|
|
477
|
+
# Get binary encoding
|
|
478
|
+
bytes_data = to_bytes(data)
|
|
479
|
+
print(f'Bytes: {bytes_data.hex()}')
|
|
480
|
+
|
|
481
|
+
# Hash
|
|
482
|
+
hash_result = hash_bytes(bytes_data)
|
|
483
|
+
print(f'Hash: {hash_result.value}')
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
## Development
|
|
487
|
+
|
|
488
|
+
### Setup with venv
|
|
489
|
+
|
|
490
|
+
```bash
|
|
491
|
+
# Create and activate virtual environment
|
|
492
|
+
python3 -m venv venv
|
|
493
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
494
|
+
|
|
495
|
+
# Install with dev dependencies
|
|
496
|
+
pip install -e ".[dev]"
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Running Tests
|
|
500
|
+
|
|
501
|
+
```bash
|
|
502
|
+
# Run all tests
|
|
503
|
+
pytest
|
|
504
|
+
|
|
505
|
+
# Run with verbose output
|
|
506
|
+
pytest -v
|
|
507
|
+
|
|
508
|
+
# Run specific test file
|
|
509
|
+
pytest tests/test_cross_language.py
|
|
510
|
+
|
|
511
|
+
# Run with coverage
|
|
512
|
+
pytest --cov=constellation_sdk
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### Code Quality
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
# Type checking
|
|
519
|
+
mypy src
|
|
520
|
+
|
|
521
|
+
# Format code
|
|
522
|
+
black src tests
|
|
523
|
+
isort src tests
|
|
524
|
+
|
|
525
|
+
# Lint
|
|
526
|
+
ruff check src tests
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
## License
|
|
530
|
+
|
|
531
|
+
Apache-2.0
|