updated multiple owner docs and cryptoconditions example

This commit is contained in:
diminator 2016-04-18 17:18:10 +02:00
parent 079a5296ce
commit 2fdbb5bef8
No known key found for this signature in database
GPG Key ID: C3D8590E6D0D439A
4 changed files with 441 additions and 153 deletions

View File

@ -70,51 +70,51 @@ After a couple of seconds, we can check if the transactions was included in the
tx_retrieved = b.get_transaction(tx_signed['id'])
{
"id": "cdb6331f26ecec0ee7e67e4d5dcd63734e7f75bbd1ebe40699fc6d2960ae4cb2",
"transaction": {
"conditions": [
"id":"933cd83a419d2735822a2154c84176a2f419cbd449a74b94e592ab807af23861",
"transaction":{
"conditions":[
{
"cid": 0,
"condition": {
"details": {
"bitmask": 32,
"public_key": "DTJCqP3sNkZcpoSA8bCtGwZ4ASfRLsMFXZDCmMHzCoeJ",
"signature": null,
"type": "fulfillment",
"type_id": 4
"cid":0,
"condition":{
"details":{
"bitmask":32,
"public_key":"BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs",
"signature":null,
"type":"fulfillment",
"type_id":4
},
"uri": "cc:1:20:uQjL_E_uT1yUsJpVi1X7x2G7B15urzIlKN5fUufehTM:98"
"uri":"cc:4:20:oqXTWvR3afHHX8OaOO84kZxS6nH4GEBXD4Vw8Mc5iBo:96"
},
"new_owners": [
"DTJCqP3sNkZcpoSA8bCtGwZ4ASfRLsMFXZDCmMHzCoeJ"
"new_owners":[
"BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs"
]
}
],
"data": {
"hash": "872fa6e6f46246cd44afdb2ee9cfae0e72885fb0910e2bcf9a5a2a4eadb417b8",
"payload": {
"msg": "Hello BigchainDB!"
"data":{
"hash":"872fa6e6f46246cd44afdb2ee9cfae0e72885fb0910e2bcf9a5a2a4eadb417b8",
"payload":{
"msg":"Hello BigchainDB!"
}
},
"fulfillments": [
"fulfillments":[
{
"current_owners": [
"current_owners":[
"3LQ5dTiddXymDhNzETB1rEkp4mA7fEV1Qeiu5ghHiJm9"
],
"fid": 0,
"fulfillment": "cf:1:4:ICKvgXHM8K2jNlKRfkwz3cCvH0OiF5A_-riWsQWXffOMQCyqbFgSDfKTaKRQHypHr5z5jsXzCQ4dKgYkmUo55CMxYs3TT2OxGiV0bZ7Tzn1lcLhpyutGZWm8xIyJKJmmSQQ",
"input": null
"fid":0,
"fulfillment":"cf:4:Iq-BcczwraM2UpF-TDPdwK8fQ6IXkD_6uJaxBZd984yxCGX7Csx-S2FBVe8LVyW2sAtmjsOSV0oiw9-s_9qSJB0dDUl_x8YQk5yxNdQyNVWVM1mWSGQL68gMngdmFG8O",
"input":null
}
],
"operation": "CREATE",
"timestamp": "1460450439.267737"
"operation":"CREATE",
"timestamp":"1460981667.449279"
},
"version": 1
"version":1
}
```
The new owner of the digital asset is now `DTJCqP3sNkZcpoSA8bCtGwZ4ASfRLsMFXZDCmMHzCoeJ`, which is the public key of `testuser1`.
The new owner of the digital asset is now `BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs`, which is the public key of `testuser1`.
Note that the current owner with public key `3LQ5dTiddXymDhNzETB1rEkp4mA7fEV1Qeiu5ghHiJm9` refers to one of the federation nodes that actually created the asset and assigned it to `testuser1`.
@ -130,9 +130,11 @@ testuser2_priv, testuser2_pub = crypto.generate_key_pair()
# retrieve the transaction with condition id
tx_retrieved_id = b.get_owned_ids(testuser1_pub).pop()
{'cid': 0,
'txid': 'cdb6331f26ecec0ee7e67e4d5dcd63734e7f75bbd1ebe40699fc6d2960ae4cb2'}
{
"cid":0,
"txid":"933cd83a419d2735822a2154c84176a2f419cbd449a74b94e592ab807af23861"
}
# create a transfer transaction
tx_transfer = b.create_transaction(testuser1_pub, testuser2_pub, tx_retrieved_id, 'TRANSFER')
@ -147,44 +149,44 @@ b.write_transaction(tx_transfer_signed)
tx_transfer_retrieved = b.get_transaction(tx_transfer_signed['id'])
{
"id": "86ce10d653c69acf422a6d017a4ccd27168cdcdac99a49e4a38fb5e0d280c579",
"transaction": {
"conditions": [
"id":"aa11365317cb89bfdae2375bae76d6b8232008f8672507080e3766ca06976dcd",
"transaction":{
"conditions":[
{
"cid": 0,
"condition": {
"details": {
"bitmask": 32,
"public_key": "7MUjLUFEu12Hk5jb8BZEFgM5JWgSya47SVbqzDqF6ZFQ",
"signature": null,
"type": "fulfillment",
"type_id": 4
"cid":0,
"condition":{
"details":{
"bitmask":32,
"public_key":"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor",
"signature":null,
"type":"fulfillment",
"type_id":4
},
"uri": "cc:1:20:XmUXkarmpe3n17ITJpi-EFy40qvGZ1C9aWphiiRfjOs:98"
"uri":"cc:4:20:DIfyalZvV_9ukoO01mxmK3nxsfAWSKYYF33XDYkbY4E:96"
},
"new_owners": [
"7MUjLUFEu12Hk5jb8BZEFgM5JWgSya47SVbqzDqF6ZFQ"
"new_owners":[
"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor"
]
}
],
"data": null,
"fulfillments": [
"data":null,
"fulfillments":[
{
"current_owners": [
"DTJCqP3sNkZcpoSA8bCtGwZ4ASfRLsMFXZDCmMHzCoeJ"
"current_owners":[
"BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs"
],
"fid": 0,
"fulfillment": "cf:1:4:ILkIy_xP7k9clLCaVYtV-8dhuwdebq8yJSjeX1Ln3oUzQPKxMGutQV0EIRYxg81_Z6gdUHQYHkEyTKxwN7zRFjHNAnIdyU1NxqqohhFQSR-qYho-L-uqPRJcAed-SI7xwAI",
"input": {
"cid": 0,
"txid": "cdb6331f26ecec0ee7e67e4d5dcd63734e7f75bbd1ebe40699fc6d2960ae4cb2"
"fid":0,
"fulfillment":"cf:4:oqXTWvR3afHHX8OaOO84kZxS6nH4GEBXD4Vw8Mc5iBqzkVR6cFJhRvMGKa-Lc81sdYWVu0ZSMPGht-P7s6FZLkRXDqrwwInabLhjx14eABY34oHb6IyWcB-dyQnlVNEI",
"input":{
"cid":0,
"txid":"933cd83a419d2735822a2154c84176a2f419cbd449a74b94e592ab807af23861"
}
}
],
"operation": "TRANSFER",
"timestamp": "1460450449.289641"
"operation":"TRANSFER",
"timestamp":"1460981677.472037"
},
"version": 1
"version":1
}
```
@ -204,7 +206,148 @@ tx_transfer_signed2 = b.sign_transaction(tx_transfer2, testuser1_priv)
# check if the transaction is valid
b.validate_transaction(tx_transfer_signed2)
DoubleSpend: input `cdb6331f26ecec0ee7e67e4d5dcd63734e7f75bbd1ebe40699fc6d2960ae4cb2` was already spent
DoubleSpend: input `{'cid': 0, 'txid': '933cd83a419d2735822a2154c84176a2f419cbd449a74b94e592ab807af23861'}` was already spent
```
## Multiple Owners
When creating a transaction to a group of people, one can simply provide an array of `new_owners`:
```python
# Create a new asset and assign it to multiple owners
tx_multisig = b.create_transaction(b.me, [testuser1_pub, testuser2_pub], None, 'CREATE')
# Have the federation sign the transaction
tx_multisig_signed = b.sign_transaction(tx_multisig, b.me_private)
b.write_transaction(tx_multisig_signed)
# wait a few seconds for the asset to appear on the blockchain
# retrieve the transaction
tx_multisig_retrieved = b.get_transaction(tx_multisig_signed['id'])
{
"id":"a9a6e5c74ea02b8885c83125f1b74a2ba8ca42236ec5e1c358aa1053ec721ccb",
"transaction":{
"conditions":[
{
"cid":0,
"condition":{
"details":{
"bitmask":41,
"subfulfillments":[
{
"bitmask":32,
"public_key":"BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs",
"signature":null,
"type":"fulfillment",
"type_id":4,
"weight":1
},
{
"bitmask":32,
"public_key":"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor",
"signature":null,
"type":"fulfillment",
"type_id":4,
"weight":1
}
],
"threshold":2,
"type":"fulfillment",
"type_id":2
},
"uri":"cc:2:29:DpflJzUSlnTUBx8lD8QUolOA-M9nQnrGwvWSk7f3REc:206"
},
"new_owners":[
"BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs",
"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor"
]
}
],
"data":null,
"fulfillments":[
{
"current_owners":[
"3LQ5dTiddXymDhNzETB1rEkp4mA7fEV1Qeiu5ghHiJm9"
],
"fid":0,
"fulfillment":"cf:4:Iq-BcczwraM2UpF-TDPdwK8fQ6IXkD_6uJaxBZd984z5qdHRz9Jag68dkOyZS5_YoTR_0WpwiUnBGoNgwjwEuIn5JNm7Kksi0nUnHsWssyXISkmqRnHH-30HQhKjznIH",
"input":null
}
],
"operation":"CREATE",
"timestamp":"1460981687.501433"
},
"version":1
}
```
The asset can be transfered as soon as each of the `new_owners` sign the transaction.
To do so, simply provide an array of the necessary private keys to the signing routine:
```python
# create a third testuser
testuser3_priv, testuser3_pub = crypto.generate_key_pair()
# retrieve the multisig transaction
tx_multisig_retrieved_id = b.get_owned_ids(testuser2_pub).pop()
# transfer the asset from the 2 owners to the third testuser
tx_multisig_transfer = b.create_transaction([testuser1_pub, testuser2_pub], testuser3_pub, tx_multisig_retrieved_id, 'TRANSFER')
# sign with both private keys
tx_multisig_transfer_signed = b.sign_transaction(tx_multisig_transfer, [testuser1_priv, testuser2_priv])
# write to bigchain
b.write_transaction(tx_multisig_transfer_signed)
# check if the transaction exists in the bigchain
tx_multisig_retrieved = b.get_transaction(tx_multisig_transfer_signed['id'])
{
"assignee":"3LQ5dTiddXymDhNzETB1rEkp4mA7fEV1Qeiu5ghHiJm9",
"id":"e689e23f774e7c562eeb310c7c712b34fb6210bea5deb9175e48b68810029150",
"transaction":{
"conditions":[
{
"cid":0,
"condition":{
"details":{
"bitmask":32,
"public_key":"8YN9fALMj9CkeCcmTiM2kxwurpkMzHg9RkwSLJKMasvG",
"signature":null,
"type":"fulfillment",
"type_id":4
},
"uri":"cc:4:20:cAq6JQJXtwlxURqrksiyqLThB9zh08ZxSPLTDSaReYE:96"
},
"new_owners":[
"8YN9fALMj9CkeCcmTiM2kxwurpkMzHg9RkwSLJKMasvG"
]
}
],
"data":null,
"fulfillments":[
{
"current_owners":[
"BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs",
"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor"
],
"fid":0,
"fulfillment":"cf:4:oqXTWvR3afHHX8OaOO84kZxS6nH4GEBXD4Vw8Mc5iBrcuiGDNVgpH9SwiuNeYZ-nugSTbxykH8W1eH5UJiunmnBSlKnJb8_QYOQsMAXl3MyLq2pWAyI45ZSG1rr2CksI",
"input":{
"cid":0,
"txid":"aa11365317cb89bfdae2375bae76d6b8232008f8672507080e3766ca06976dcd"
}
}
],
"operation":"TRANSFER",
"timestamp":"1460981697.526878"
},
"version":1
}
```
## Crypto-Conditions
@ -238,29 +381,31 @@ The basic workflow for creating a more complex cryptocondition is the following:
2. Set up the threshold condition using the [cryptocondition library](https://github.com/bigchaindb/cryptoconditions)
3. Update the condition and hash in the transaction template
We'll illustrate this by an example:
We'll illustrate this by a threshold condition where 2 out of 3 `new_owners` need to sign the transaction:
```python
import copy
import json
from cryptoconditions import Ed25519Fulfillment, ThresholdSha256Fulfillment
import cryptoconditions as cc
from bigchaindb import util, crypto
# create some new testusers
thresholduser1_priv, thresholduser1_pub = crypto.generate_key_pair()
thresholduser2_priv, thresholduser2_pub = crypto.generate_key_pair()
thresholduser3_priv, thresholduser3_pub = crypto.generate_key_pair()
# retrieve the last transaction of testuser2
tx_retrieved_id = b.get_owned_ids(testuser2_pub).pop()
# create a base template for a 1-input/2-output transaction
threshold_tx = b.create_transaction(testuser2_pub, [thresholduser1_pub, thresholduser2_pub], tx_retrieved_id, 'TRANSFER')
threshold_tx = b.create_transaction(testuser2_pub, [thresholduser1_pub, thresholduser2_pub, thresholduser3_pub], tx_retrieved_id, 'TRANSFER')
# create a Threshold Cryptocondition
threshold_condition = ThresholdSha256Fulfillment(threshold=2)
threshold_condition.add_subfulfillment(Ed25519Fulfillment(public_key=thresholduser1_pub))
threshold_condition.add_subfulfillment(Ed25519Fulfillment(public_key=thresholduser2_pub))
threshold_condition = cc.ThresholdSha256Fulfillment(threshold=2)
threshold_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=thresholduser1_pub))
threshold_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=thresholduser2_pub))
threshold_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=thresholduser3_pub))
# update the condition in the newly created transaction
threshold_tx['transaction']['conditions'][0]['condition'] = {
@ -281,64 +426,72 @@ b.write_transaction(threshold_tx_signed)
tx_threshold_retrieved = b.get_transaction(threshold_tx_signed['id'])
{
"id": "f0ea4a96afb3b8cafd6336aa3c4b44d1bb0f2b801f61fcb6a44eea4b870ff2e2",
"transaction": {
"conditions": [
"id":"0057d29ff735d91505decf5e7195ea8da675b01676165abf23ea774bbb469383",
"transaction":{
"conditions":[
{
"cid": 0,
"condition": {
"details": {
"bitmask": 41,
"subfulfillments": [
"cid":0,
"condition":{
"details":{
"bitmask":41,
"subfulfillments":[
{
"bitmask": 32,
"public_key": "3tuSZ4FitNVWRgK7bGe6pEia7ERmxHmhCxFfFEVbD7g4",
"signature": null,
"type": "fulfillment",
"type_id": 4,
"weight": 1
"bitmask":32,
"public_key":"8NaGq26YMcEvj8Sc5MnqspKzFTQd1eZBAuuPDw4ERHpz",
"signature":null,
"type":"fulfillment",
"type_id":4,
"weight":1
},
{
"bitmask": 32,
"public_key": "8CvrriTsPZULEXTZW2Hnmg7najZsvXzgTi9NKpJaUdHS",
"signature": null,
"type": "fulfillment",
"type_id": 4,
"weight": 1
"bitmask":32,
"public_key":"ALE9Agojob28D1fHWCxFXJwpqrYPkcsUs26YksBVj27z",
"signature":null,
"type":"fulfillment",
"type_id":4,
"weight":1
},
{
"bitmask":32,
"public_key":"Cx4jWSGci7fw6z5QyeApCijbwnMpyuhp4C1kzuFc3XrM",
"signature":null,
"type":"fulfillment",
"type_id":4,
"weight":1
}
],
"threshold": 2,
"type": "fulfillment",
"type_id": 2
"threshold":2,
"type":"fulfillment",
"type_id":2
},
"uri": "cc:1:29:kiQHpdEiRe24L62KzwQgLu7dxCHaLBfEFLr_xzlswT4:208"
"uri":"cc:2:29:FoElId4TE5TU2loonT7sayXhxwcmaJVoCeIduh56Dxw:246"
},
"new_owners": [
"3tuSZ4FitNVWRgK7bGe6pEia7ERmxHmhCxFfFEVbD7g4",
"8CvrriTsPZULEXTZW2Hnmg7najZsvXzgTi9NKpJaUdHS"
"new_owners":[
"8NaGq26YMcEvj8Sc5MnqspKzFTQd1eZBAuuPDw4ERHpz",
"ALE9Agojob28D1fHWCxFXJwpqrYPkcsUs26YksBVj27z",
"Cx4jWSGci7fw6z5QyeApCijbwnMpyuhp4C1kzuFc3XrM"
]
}
],
"data": null,
"fulfillments": [
"data":null,
"fulfillments":[
{
"current_owners": [
"7MUjLUFEu12Hk5jb8BZEFgM5JWgSya47SVbqzDqF6ZFQ"
"current_owners":[
"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor"
],
"fid": 0,
"fulfillment": "cf:1:4:IF5lF5Gq5qXt59eyEyaYvhBcuNKrxmdQvWlqYYokX4zrQDSWz8yxBCFaYFKZOLai5ZCoVq28LVoiQ7TL5zkajG-I-BYH2NaKj7CfPBIZHWkMGWfd_UuQWkbhyx07MJ_1Jww",
"input": {
"cid": 0,
"txid": "86ce10d653c69acf422a6d017a4ccd27168cdcdac99a49e4a38fb5e0d280c579"
"fid":0,
"fulfillment":"cf:4:DIfyalZvV_9ukoO01mxmK3nxsfAWSKYYF33XDYkbY4EbD7-_neXJJEe_tVTDc1_EqldlP_ulysFMprcW3VG4gzLzCMMpxA8kCr_pvywSFIEVYJHnI1csMvPivvBGHvkD",
"input":{
"cid":0,
"txid":"aa11365317cb89bfdae2375bae76d6b8232008f8672507080e3766ca06976dcd"
}
}
],
"operation": "TRANSFER",
"timestamp": "1460450459.321600"
"operation":"TRANSFER",
"timestamp":"1460981707.559401"
},
"version": 1
"version":1
}
```
The transaction can now be transfered by fulfilling the threshold condition.
@ -351,29 +504,39 @@ The fulfillment involves:
```python
from cryptoconditions.fulfillment import Fulfillment
thresholduser3_priv, thresholduser3_pub = crypto.generate_key_pair()
thresholduser4_priv, thresholduser4_pub = crypto.generate_key_pair()
# retrieve the last transaction of thresholduser1_pub
tx_retrieved_id = b.get_owned_ids(thresholduser1_pub).pop()
# create a base template for a 2-input/1-output transaction
threshold_tx_transfer = b.create_transaction([thresholduser1_pub, thresholduser2_pub], thresholduser3_pub, tx_retrieved_id, 'TRANSFER')
threshold_tx_transfer = b.create_transaction([thresholduser1_pub, thresholduser2_pub, thresholduser3_pub], thresholduser4_pub, tx_retrieved_id, 'TRANSFER')
# parse the threshold cryptocondition
threshold_fulfillment = Fulfillment.from_json(threshold_tx['transaction']['conditions'][0]['condition']['details'])
subfulfillment1 = threshold_fulfillment.subconditions[0]['body']
subfulfillment2 = threshold_fulfillment.subconditions[1]['body']
threshold_fulfillment = cc.Fulfillment.from_json(threshold_tx['transaction']['conditions'][0]['condition']['details'])
subfulfillment1 = threshold_fulfillment.get_subcondition_from_vk(thresholduser1_pub)[0]
subfulfillment2 = threshold_fulfillment.get_subcondition_from_vk(thresholduser2_pub)[0]
subfulfillment3 = threshold_fulfillment.get_subcondition_from_vk(thresholduser3_pub)[0]
# get the fulfillment message to sign
threshold_tx_fulfillment_message = util.get_fulfillment_message(threshold_tx_transfer,
threshold_tx_transfer['transaction']['fulfillments'][0],
serialized=True)
# sign the subconditions
# clear the subconditions of the threshold fulfillment, they will be added again after signing
threshold_fulfillment.subconditions = []
# sign and add the subconditions until threshold of 2 is reached
subfulfillment1.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser1_priv))
threshold_fulfillment.add_subfulfillment(subfulfillment1)
subfulfillment2.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser2_priv))
threshold_fulfillment.add_subfulfillment(subfulfillment2)
# Add remaining (unfulfilled) fulfillment as a condition
threshold_fulfillment.add_subcondition(subfulfillment3.condition)
# update the fulfillment
threshold_tx_transfer['transaction']['fulfillments'][0]['fulfillment'] = threshold_fulfillment.serialize_uri()
@ -386,45 +549,48 @@ assert b.validate_transaction(threshold_tx_transfer) == True
b.write_transaction(threshold_tx_transfer)
{
"id": "27d1e780526e172fdafb6cfec24b43878b0f8a2c34e962546ba4932ef7662646",
"transaction": {
"conditions": [
"assignee":"3LQ5dTiddXymDhNzETB1rEkp4mA7fEV1Qeiu5ghHiJm9",
"id":"a45b2340c59df7422a5788b3c462dee708a18cdf09d1a10bd26be3f31af4b8d7",
"transaction":{
"conditions":[
{
"cid": 0,
"condition": {
"details": {
"bitmask": 32,
"public_key": "4SwVNiYRykGw1ixgKH75k97ipCnmm5QpwNwzQdCKLCzH",
"signature": null,
"type": "fulfillment",
"type_id": 4
"cid":0,
"condition":{
"details":{
"bitmask":32,
"public_key":"ED2pyPfsbNRTHkdMnaFkAwCSpZWRmbaM1h8fYzgRRMmc",
"signature":null,
"type":"fulfillment",
"type_id":4
},
"uri": "cc:1:20:MzgxMS8Zt2XZrSA_dFk1d64nwUz16knOeKkxc5LyIv4:98"
"uri":"cc:4:20:xDz3NhRG-3eVzIB9sgnd99LKjOyDF-KlxWuf1TgNT0s:96"
},
"new_owners": [
"4SwVNiYRykGw1ixgKH75k97ipCnmm5QpwNwzQdCKLCzH"
"new_owners":[
"ED2pyPfsbNRTHkdMnaFkAwCSpZWRmbaM1h8fYzgRRMmc"
]
}
],
"data": null,
"fulfillments": [
"data":null,
"fulfillments":[
{
"current_owners": [
"3tuSZ4FitNVWRgK7bGe6pEia7ERmxHmhCxFfFEVbD7g4",
"8CvrriTsPZULEXTZW2Hnmg7najZsvXzgTi9NKpJaUdHS"
"current_owners":[
"8NaGq26YMcEvj8Sc5MnqspKzFTQd1eZBAuuPDw4ERHpz",
"ALE9Agojob28D1fHWCxFXJwpqrYPkcsUs26YksBVj27z",
"Cx4jWSGci7fw6z5QyeApCijbwnMpyuhp4C1kzuFc3XrM"
],
"fid": 0,
"fulfillment": "cf:1:2:AgIBYwQgKwNKM5oJUhL3lUJ3Xj0dzePTH_1BOxcIry5trRxnNXFANabre0P23pzs3liGozZ-cua3zLZuZIc4UA-2Eb_3oi0zFZKHlL6_PrfxpZFp4Mafsl3Iz1yGVz8s-x5jcbahDwABYwQgaxAYvRMOihIk-M4AZYFB2mlf4XjEqhiOaWpqinOYiXFAuQm7AMeXDs4NCeFI4P6YeL3RqNZqyTr9OsNHZ9JgJLZ2ER1nFpwsLhOt4TJZ01Plon7r7xA2GFKFkw511bRWAQA",
"input": {
"cid": 0,
"txid": "f0ea4a96afb3b8cafd6336aa3c4b44d1bb0f2b801f61fcb6a44eea4b870ff2e2"
"fid":0,
"fulfillment":"cf:2:AQIBAwEBACcABAEgILGLuLLaNHo-KE59tkrpYmlVeucu16Eg9TcSuBqnMVwmAWABAWMABGBtiKCT8NBtSdnxJNdGYkyWqoRy2qOeNZ5UdUvpALcBD4vGRaohuVP9pQYNHpAA5GjTNNQT9CVMB67D8QL_DJsRU8ICSIVIG2P8pRqX6oia-304Xqq67wY-wLh_3IKlUg0AAQFjAARgiqYTeWkT6-jRMriCK4i8ceE2TwPys0JXgIrbw4kbwElVNnc7Aqw5c-Ts8-ymLp3d9_xTIb3-mPaV4JjhBqcobKuq2msJAjrxZOEeuYuAyC0tpduwTajOyp_Kmwzhdm8PAA",
"input":{
"cid":0,
"txid":"0057d29ff735d91505decf5e7195ea8da675b01676165abf23ea774bbb469383"
}
}
],
"operation": "TRANSFER",
"timestamp": "1460450469.337543"
"operation":"TRANSFER",
"timestamp":"1460981717.579700"
},
"version": 1
"version":1
}
```

View File

@ -71,7 +71,7 @@ setup(
'rethinkdb==2.2.0.post4',
'pysha3==0.3',
'pytz==2015.7',
'cryptoconditions==0.2.0',
'cryptoconditions==0.2.1',
'statsd==3.2.1',
'python-rapidjson==0.0.6',
'logstats==0.2.1',

View File

@ -1310,7 +1310,7 @@ class TestCryptoconditions(object):
first_tx_fulfillment.sign(first_tx_fulfillment_message, crypto.SigningKey(user_sk))
first_tx['transaction']['fulfillments'][0]['fulfillment'] = first_tx_fulfillment.serialize_uri()
assert b.validate_transaction(first_tx)
assert b.validate_transaction(first_tx) == first_tx
assert b.is_valid_transaction(first_tx) == first_tx
b.write_transaction(first_tx)
@ -1329,20 +1329,22 @@ class TestCryptoconditions(object):
next_tx_fulfillment.sign(next_tx_fulfillment_message, crypto.SigningKey(other_sk))
next_tx['transaction']['fulfillments'][0]['fulfillment'] = next_tx_fulfillment.serialize_uri()
assert b.validate_transaction(next_tx)
assert b.validate_transaction(next_tx) == next_tx
assert b.is_valid_transaction(next_tx) == next_tx
@pytest.mark.usefixtures('inputs')
def test_override_condition_and_fulfillment_transfer_threshold(self, b, user_vk, user_sk):
other1_sk, other1_vk = crypto.generate_key_pair()
other2_sk, other2_vk = crypto.generate_key_pair()
other3_sk, other3_vk = crypto.generate_key_pair()
first_input_tx = b.get_owned_ids(user_vk).pop()
first_tx = b.create_transaction(user_vk, [other1_vk, other2_vk], first_input_tx, 'TRANSFER')
first_tx = b.create_transaction(user_vk, [other1_vk, other2_vk, other3_vk], first_input_tx, 'TRANSFER')
first_tx_condition = cc.ThresholdSha256Fulfillment(threshold=2)
first_tx_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=other1_vk))
first_tx_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=other2_vk))
first_tx_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=other3_vk))
first_tx['transaction']['conditions'][0]['condition'] = {
'details': json.loads(first_tx_condition.serialize_json()),
@ -1353,7 +1355,7 @@ class TestCryptoconditions(object):
first_tx_signed = b.sign_transaction(first_tx, user_sk)
assert b.validate_transaction(first_tx_signed)
assert b.validate_transaction(first_tx_signed) == first_tx_signed
assert b.is_valid_transaction(first_tx_signed) == first_tx_signed
b.write_transaction(first_tx_signed)
@ -1364,7 +1366,7 @@ class TestCryptoconditions(object):
next_input_tx = b.get_owned_ids(other1_vk).pop()
# create another transaction with the same input
next_tx = b.create_transaction([other1_vk, other2_vk], user_vk, next_input_tx, 'TRANSFER')
next_tx = b.create_transaction([other1_vk, other2_vk, other3_vk], user_vk, next_input_tx, 'TRANSFER')
next_tx_fulfillment = next_tx['transaction']['fulfillments'][0]
next_tx_fulfillment_message = util.get_fulfillment_message(next_tx, next_tx_fulfillment, serialized=True)
@ -1375,9 +1377,70 @@ class TestCryptoconditions(object):
next_tx_subfulfillment2 = cc.Ed25519Fulfillment(public_key=other2_vk)
next_tx_subfulfillment2.sign(next_tx_fulfillment_message, crypto.SigningKey(other2_sk))
next_tx_fulfillment.add_subfulfillment(next_tx_subfulfillment2)
# need to add remaining (unsigned) fulfillment as a condition
next_tx_subfulfillment3 = cc.Ed25519Fulfillment(public_key=other3_vk)
next_tx_fulfillment.add_subcondition(next_tx_subfulfillment3.condition)
next_tx['transaction']['fulfillments'][0]['fulfillment'] = next_tx_fulfillment.serialize_uri()
assert b.validate_transaction(next_tx)
assert b.validate_transaction(next_tx) == next_tx
assert b.is_valid_transaction(next_tx) == next_tx
@pytest.mark.usefixtures('inputs')
def test_override_condition_and_fulfillment_transfer_threshold_from_json(self, b, user_vk, user_sk):
other1_sk, other1_vk = crypto.generate_key_pair()
other2_sk, other2_vk = crypto.generate_key_pair()
other3_sk, other3_vk = crypto.generate_key_pair()
first_input_tx = b.get_owned_ids(user_vk).pop()
first_tx = b.create_transaction(user_vk, [other1_vk, other2_vk, other3_vk], first_input_tx, 'TRANSFER')
first_tx_condition = cc.ThresholdSha256Fulfillment(threshold=2)
first_tx_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=other1_vk))
first_tx_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=other2_vk))
first_tx_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=other3_vk))
first_tx['transaction']['conditions'][0]['condition'] = {
'details': json.loads(first_tx_condition.serialize_json()),
'uri': first_tx_condition.condition.serialize_uri()
}
# conditions have been updated, so hash needs updating
first_tx['id'] = util.get_hash_data(first_tx)
first_tx_signed = b.sign_transaction(first_tx, user_sk)
assert b.validate_transaction(first_tx_signed) == first_tx_signed
assert b.is_valid_transaction(first_tx_signed) == first_tx_signed
b.write_transaction(first_tx_signed)
# create and write block to bigchain
block = b.create_block([first_tx])
b.write_block(block, durability='hard')
next_input_tx = b.get_owned_ids(other1_vk).pop()
# create another transaction with the same input
next_tx = b.create_transaction([other1_vk, other2_vk, other3_vk], user_vk, next_input_tx, 'TRANSFER')
next_tx_fulfillment = next_tx['transaction']['fulfillments'][0]
next_tx_fulfillment_message = util.get_fulfillment_message(next_tx, next_tx_fulfillment, serialized=True)
# parse the threshold cryptocondition
next_tx_fulfillment = cc.Fulfillment.from_json(first_tx['transaction']['conditions'][0]['condition']['details'])
subfulfillment1 = next_tx_fulfillment.get_subcondition_from_vk(other1_vk)[0]
subfulfillment2 = next_tx_fulfillment.get_subcondition_from_vk(other2_vk)[0]
subfulfillment3 = next_tx_fulfillment.get_subcondition_from_vk(other3_vk)[0]
next_tx_fulfillment.subconditions = []
# sign the subconditions until threshold of 2 is reached
subfulfillment1.sign(next_tx_fulfillment_message, crypto.SigningKey(other1_sk))
next_tx_fulfillment.add_subfulfillment(subfulfillment1)
subfulfillment2.sign(next_tx_fulfillment_message, crypto.SigningKey(other2_sk))
next_tx_fulfillment.add_subfulfillment(subfulfillment2)
next_tx_fulfillment.add_subcondition(subfulfillment3.condition)
next_tx['transaction']['fulfillments'][0]['fulfillment'] = next_tx_fulfillment.serialize_uri()
assert b.validate_transaction(next_tx) == next_tx
assert b.is_valid_transaction(next_tx) == next_tx
@pytest.mark.usefixtures('inputs')
@ -1401,7 +1464,7 @@ class TestCryptoconditions(object):
first_tx_signed = b.sign_transaction(first_tx, user_sk)
assert b.validate_transaction(first_tx_signed)
assert b.validate_transaction(first_tx_signed) == first_tx_signed
assert b.is_valid_transaction(first_tx_signed) == first_tx_signed
b.write_transaction(first_tx_signed)

View File

@ -31,11 +31,18 @@ sleep(10)
tx_retrieved = b.get_transaction(tx_signed['id'])
print(json.dumps(tx_retrieved, sort_keys=True, indent=4, separators=(',', ':')))
print(testuser1_pub)
print(b.me)
print(tx_retrieved['id'])
# create a second testuser
testuser2_priv, testuser2_pub = crypto.generate_key_pair()
# retrieve the transaction with condition id
tx_retrieved_id = b.get_owned_ids(testuser1_pub).pop()
print(json.dumps(tx_retrieved_id, sort_keys=True, indent=4, separators=(',', ':')))
# create a transfer transaction
tx_transfer = b.create_transaction(testuser1_pub, testuser2_pub, tx_retrieved_id, 'TRANSFER')
@ -50,6 +57,8 @@ sleep(10)
# check if the transaction is already in the bigchain
tx_transfer_retrieved = b.get_transaction(tx_transfer_signed['id'])
print(json.dumps(tx_transfer_retrieved, sort_keys=True, indent=4, separators=(',', ':')))
# create another transfer transaction with the same input
tx_transfer2 = b.create_transaction(testuser1_pub, testuser2_pub, tx_retrieved_id, 'TRANSFER')
@ -63,20 +72,54 @@ try:
except exceptions.DoubleSpend as e:
print(e)
# Create a new asset and assign it to multiple owners
tx_multisig = b.create_transaction(b.me, [testuser1_pub, testuser2_pub], None, 'CREATE')
# Have the federation sign the transaction
tx_multisig_signed = b.sign_transaction(tx_multisig, b.me_private)
b.write_transaction(tx_multisig_signed)
# wait a few seconds for the asset to appear on the blockchain
sleep(10)
# retrieve the transaction
tx_multisig_retrieved = b.get_transaction(tx_multisig_signed['id'])
print(json.dumps(tx_multisig_retrieved, sort_keys=True, indent=4, separators=(',', ':')))
testuser3_priv, testuser3_pub = crypto.generate_key_pair()
tx_multisig_retrieved_id = b.get_owned_ids(testuser2_pub).pop()
tx_multisig_transfer = b.create_transaction([testuser1_pub, testuser2_pub], testuser3_pub, tx_multisig_retrieved_id, 'TRANSFER')
tx_multisig_transfer_signed = b.sign_transaction(tx_multisig_transfer, [testuser1_priv, testuser2_priv])
b.write_transaction(tx_multisig_transfer_signed)
# wait a few seconds for the asset to appear on the blockchain
sleep(10)
# retrieve the transaction
tx_multisig_retrieved = b.get_transaction(tx_multisig_transfer_signed['id'])
print(json.dumps(tx_multisig_transfer_signed, sort_keys=True, indent=4, separators=(',', ':')))
# create some new testusers
thresholduser1_priv, thresholduser1_pub = crypto.generate_key_pair()
thresholduser2_priv, thresholduser2_pub = crypto.generate_key_pair()
thresholduser3_priv, thresholduser3_pub = crypto.generate_key_pair()
# retrieve the last transaction of testuser2
tx_retrieved_id = b.get_owned_ids(testuser2_pub).pop()
# create a base template for a 1-input/2-output transaction
threshold_tx = b.create_transaction(testuser2_pub, [thresholduser1_pub, thresholduser2_pub], tx_retrieved_id, 'TRANSFER')
# create a base template for a 1-input/3-output transaction
threshold_tx = b.create_transaction(testuser2_pub, [thresholduser1_pub, thresholduser2_pub, thresholduser3_pub],
tx_retrieved_id, 'TRANSFER')
# create a Threshold Cryptocondition
# create a 2-out-of-3 Threshold Cryptocondition
threshold_condition = ThresholdSha256Fulfillment(threshold=2)
threshold_condition.add_subfulfillment(Ed25519Fulfillment(public_key=thresholduser1_pub))
threshold_condition.add_subfulfillment(Ed25519Fulfillment(public_key=thresholduser2_pub))
threshold_condition.add_subfulfillment(Ed25519Fulfillment(public_key=thresholduser3_pub))
# update the condition in the newly created transaction
threshold_tx['transaction']['conditions'][0]['condition'] = {
@ -97,28 +140,41 @@ sleep(10)
# check if the transaction is already in the bigchain
tx_threshold_retrieved = b.get_transaction(threshold_tx_signed['id'])
print(json.dumps(tx_threshold_retrieved, sort_keys=True, indent=4, separators=(',', ':')))
thresholduser3_priv, thresholduser3_pub = crypto.generate_key_pair()
thresholduser4_priv, thresholduser4_pub = crypto.generate_key_pair()
# retrieve the last transaction of thresholduser1_pub
tx_retrieved_id = b.get_owned_ids(thresholduser1_pub).pop()
# create a base template for a 2-input/1-output transaction
threshold_tx_transfer = b.create_transaction([thresholduser1_pub, thresholduser2_pub], thresholduser3_pub, tx_retrieved_id, 'TRANSFER')
threshold_tx_transfer = b.create_transaction([thresholduser1_pub, thresholduser2_pub, thresholduser3_pub],
thresholduser4_pub, tx_retrieved_id, 'TRANSFER')
# parse the threshold cryptocondition
threshold_fulfillment = Fulfillment.from_json(threshold_tx['transaction']['conditions'][0]['condition']['details'])
subfulfillment1 = threshold_fulfillment.subconditions[0]['body']
subfulfillment2 = threshold_fulfillment.subconditions[1]['body']
subfulfillment1 = threshold_fulfillment.get_subcondition_from_vk(thresholduser1_pub)[0]
subfulfillment2 = threshold_fulfillment.get_subcondition_from_vk(thresholduser2_pub)[0]
subfulfillment3 = threshold_fulfillment.get_subcondition_from_vk(thresholduser3_pub)[0]
# get the fulfillment message to sign
threshold_tx_fulfillment_message = util.get_fulfillment_message(threshold_tx_transfer,
threshold_tx_transfer['transaction']['fulfillments'][0],
serialized=True)
# sign the subconditions
# clear the subconditions of the threshold fulfillment, they will be added again after signing
threshold_fulfillment.subconditions = []
# sign and add the subconditions until threshold of 2 is reached
subfulfillment1.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser1_priv))
threshold_fulfillment.add_subfulfillment(subfulfillment1)
subfulfillment2.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser2_priv))
threshold_fulfillment.add_subfulfillment(subfulfillment2)
# Add remaining (unfulfilled) fulfillment as a condition
threshold_fulfillment.add_subcondition(subfulfillment3.condition)
assert threshold_fulfillment.validate(threshold_tx_fulfillment_message) == True
@ -126,7 +182,10 @@ threshold_tx_transfer['transaction']['fulfillments'][0]['fulfillment'] = thresho
assert b.verify_signature(threshold_tx_transfer) == True
assert b.validate_transaction(threshold_tx_transfer) == True
assert b.validate_transaction(threshold_tx_transfer) == threshold_tx_transfer
b.write_transaction(threshold_tx_transfer)
print(json.dumps(threshold_tx_transfer, sort_keys=True, indent=4, separators=(',', ':')))