|
15 | 15 |
|
16 | 16 | from typing import List |
17 | 17 |
|
18 | | -from iota import Address, ProposedTransaction, Tag, TransactionTrytes, \ |
19 | | - TryteString |
20 | | -from iota.crypto.types import Digest, Seed |
| 18 | +from iota import Address, Bundle, BundleValidator, ProposedTransaction, Tag, \ |
| 19 | + TransactionTrytes, TryteString |
| 20 | +from iota.crypto.types import Digest, PrivateKey, Seed |
21 | 21 | from iota.multisig import MultisigIota |
22 | 22 | from iota.multisig.types import MultisigAddress |
23 | 23 |
|
|
181 | 181 |
|
182 | 182 | Note that we must apply signatures in the same order as when we created |
183 | 183 | the multisig address! |
| 184 | +
|
| 185 | +This step normally happens on separate computers, so that participants |
| 186 | +don't have to share their private keys (except when doing m-of-n). |
| 187 | +
|
| 188 | +https://github.com/iotaledger/wiki/blob/master/multisigs.md#how-m-of-n-works |
| 189 | +
|
| 190 | +For this example, the structure of the bundle looks like this: |
| 191 | +
|
| 192 | +- Transaction 0: Spend IOTAs. |
| 193 | +- Transactions 1-8: Transactions that will hold the signature |
| 194 | + fragments for the multisig input: |
| 195 | + - 1-3: Generated from ``digest_1`` (security level 3). |
| 196 | + - 4-6: Generated from ``digest_2`` (security level 3). |
| 197 | + - 7-8: Generated from ``digest_3`` (security level 2). |
| 198 | +
|
| 199 | +Note that transactions 1-8 don't have signatures yet; we need the |
| 200 | +corresponding private keys in order to create those! |
184 | 201 | """ |
185 | | -# :todo: |
186 | | -signed_trytes = None # type: List[TransactionTrytes] |
| 202 | +bundle = Bundle.from_tryte_strings(prepared_trytes) |
| 203 | + |
| 204 | +# Note that we must use the same parameters that we provided to the |
| 205 | +# ``get_digests`` method, in order to generate the correct value to |
| 206 | +# sign the input! |
| 207 | +gpk_result = api_1.get_private_keys(index=0, count=1, security_level=3) |
| 208 | +private_key_1 = gpk_result['keys'][0] # type: PrivateKey |
| 209 | +private_key_1.sign_input_transactions(bundle, 1) |
| 210 | + |
| 211 | +gpk_result = api_2.get_private_keys(index=42, count=1, security_level=3) |
| 212 | +private_key_2 = gpk_result['keys'][0] # type: PrivateKey |
| 213 | +private_key_2.sign_input_transactions(bundle, 4) |
187 | 214 |
|
| 215 | +gpk_result = api_3.get_private_keys(index=8, count=1, security_level=2) |
| 216 | +private_key_3 = gpk_result['keys'][0] # type: PrivateKey |
| 217 | +private_key_3.sign_input_transactions(bundle, 7) |
| 218 | + |
| 219 | +# Once we've applied the signatures, convert the Bundle back into tryte |
| 220 | +# sequences so that we can broadcast them to the tangle. |
| 221 | +signed_trytes = bundle.as_tryte_strings() |
| 222 | + |
| 223 | +""" |
| 224 | +Step 4.5 (Optional): Validate the signatures. |
| 225 | +
|
| 226 | +This step is purely optional. We are including it in this example |
| 227 | +script so that you can see that the resulting signature fragments are |
| 228 | +valid. |
| 229 | +""" |
| 230 | +validator = BundleValidator(bundle) |
| 231 | +if not validator.is_valid(): |
| 232 | + raise ValueError( |
| 233 | + 'Bundle failed validation:\n{errors}'.format( |
| 234 | + errors = '\n'.join((' - ' + e) for e in validator.errors), |
| 235 | + ), |
| 236 | + ) |
188 | 237 |
|
189 | 238 | """ |
190 | 239 | Step 5: Broadcast the bundle. |
|
0 commit comments