mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
WIP: docs and tutorial
This commit is contained in:
parent
9875cab3b3
commit
37c698529f
@ -238,23 +238,6 @@ class Bigchain(object):
|
||||
.run(self.conn)
|
||||
owned = []
|
||||
|
||||
def owner_in_subfulfillments(condition_details, _owner):
|
||||
if 'subfulfillments' in condition_details:
|
||||
result = owner_in_subfulfillments(condition_details['subfulfillments'], _owner)
|
||||
if result:
|
||||
return True
|
||||
|
||||
elif isinstance(condition_details, list):
|
||||
for _subfulfillment in condition_details:
|
||||
result = owner_in_subfulfillments(_subfulfillment, _owner)
|
||||
if result:
|
||||
return True
|
||||
else:
|
||||
if 'public_key' in condition_details \
|
||||
and _owner == condition_details['public_key']:
|
||||
return True
|
||||
return False
|
||||
|
||||
for tx in response:
|
||||
# a transaction can contain multiple outputs (conditions) so we need to iterate over all of them
|
||||
# to get a list of outputs available to spend
|
||||
@ -268,7 +251,7 @@ class Bigchain(object):
|
||||
# for transactions with multiple `new_owners` there will be several subfulfillments nested
|
||||
# in the condition. We need to iterate the subfulfillments to make sure there is a
|
||||
# subfulfillment for `owner`
|
||||
if owner_in_subfulfillments(condition['condition']['details'], owner):
|
||||
if util.condition_details_has_owner(condition['condition']['details'], owner):
|
||||
tx_input = {'txid': tx['id'], 'cid': condition['cid']}
|
||||
# check if input was already spent
|
||||
if not self.get_spent(tx_input):
|
||||
|
@ -526,6 +526,37 @@ def get_input_condition(bigchain, fulfillment):
|
||||
}
|
||||
|
||||
|
||||
def condition_details_has_owner(condition_details, owner):
|
||||
"""
|
||||
|
||||
Check if the public_key of owner is in the condition details
|
||||
as an Ed25519Fulfillment.public_key
|
||||
|
||||
Args:
|
||||
condition_details (dict): dict with condition details
|
||||
owner (str): base58 public key of owner
|
||||
|
||||
Returns:
|
||||
bool: True if the public key is found in the condition details, False otherwise
|
||||
|
||||
"""
|
||||
if 'subfulfillments' in condition_details:
|
||||
result = condition_details_has_owner(condition_details['subfulfillments'], owner)
|
||||
if result:
|
||||
return True
|
||||
|
||||
elif isinstance(condition_details, list):
|
||||
for subcondition in condition_details:
|
||||
result = condition_details_has_owner(subcondition, owner)
|
||||
if result:
|
||||
return True
|
||||
else:
|
||||
if 'public_key' in condition_details \
|
||||
and owner == condition_details['public_key']:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def get_hash_data(transaction):
|
||||
""" Get the hashed data that (should) correspond to the `transaction['id']`
|
||||
|
||||
|
BIN
docs/source/_static/cc_escrow_execute_abort.png
Normal file
BIN
docs/source/_static/cc_escrow_execute_abort.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
docs/source/_static/tx_escrow_execute_abort.png
Normal file
BIN
docs/source/_static/tx_escrow_execute_abort.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
Binary file not shown.
@ -885,4 +885,204 @@ hashlock_fulfill_tx
|
||||
},
|
||||
"version":1
|
||||
}
|
||||
```
|
||||
|
||||
### Timeout Conditions
|
||||
|
||||
Timeout conditions allow assets to expire after a certain time.
|
||||
The primary use case of timeout conditions is to enable Escrow (see further).
|
||||
|
||||
The condition can only be fulfilled before the expiry time.
|
||||
Once expired, the asset is lost and cannot be fulfilled by anyone.
|
||||
|
||||
__Note__: The timeout conditions are BigchainDB-specific and not (yet) supported by the ILP standard.
|
||||
|
||||
```python
|
||||
# Create a timeout asset without any new_owners
|
||||
timeout_tx = b.create_transaction(b.me, None, None, 'CREATE')
|
||||
|
||||
# Set expiry time - the asset needs to be transfered before expiration
|
||||
time_sleep = 12
|
||||
time_expire = str(float(util.timestamp()) + time_sleep) # 12 secs from now
|
||||
condition_timeout = cc.TimeoutFulfillment(expire_time=time_expire)
|
||||
|
||||
# The conditions list is empty, so we need to append a new condition
|
||||
tx_timeout['transaction']['conditions'].append({
|
||||
'condition': {
|
||||
'details': json.loads(condition_timeout.serialize_json()),
|
||||
'uri': condition_timeout.condition.serialize_uri()
|
||||
},
|
||||
'cid': 0,
|
||||
'new_owners': None
|
||||
})
|
||||
|
||||
# Conditions have been updated, so the hash needs updating
|
||||
tx_timeout['id'] = util.get_hash_data(tx_timeout)
|
||||
|
||||
# The asset needs to be signed by the current_owner
|
||||
tx_timeout_signed = b.sign_transaction(tx_timeout, b.me_private)
|
||||
|
||||
# Some validations
|
||||
assert b.validate_transaction(tx_timeout_signed) == tx_timeout_signed
|
||||
assert b.is_valid_transaction(tx_timeout_signed) == tx_timeout_signed
|
||||
|
||||
b.write_transaction(tx_timeout_signed)
|
||||
tx_timeout_signed
|
||||
```
|
||||
|
||||
```python
|
||||
{
|
||||
"id":"78145396cd368f7168fb01c97aaf1df6f85244d7b544073dfcb42397dae38f90",
|
||||
"transaction":{
|
||||
"conditions":[
|
||||
{
|
||||
"cid":0,
|
||||
"condition":{
|
||||
"details":{
|
||||
"bitmask":9,
|
||||
"expire_time":"1464167910.643431",
|
||||
"type":"fulfillment",
|
||||
"type_id":99
|
||||
},
|
||||
"uri":"cc:63:9:sceU_NZc3cAjAvaR1TVmgj7am5y8hJEBoqLm-tbqGbQ:17"
|
||||
},
|
||||
"new_owners":null
|
||||
}
|
||||
],
|
||||
"data":null,
|
||||
"fulfillments":[
|
||||
{
|
||||
"current_owners":[
|
||||
"FmLm6MxCABc8TsiZKdeYaZKo5yZWMM6Vty7Q1B6EgcP2"
|
||||
],
|
||||
"fid":0,
|
||||
"fulfillment":null,
|
||||
"input":null
|
||||
}
|
||||
],
|
||||
"operation":"CREATE",
|
||||
"timestamp":"1464167898.643353"
|
||||
},
|
||||
"version":1
|
||||
}
|
||||
```
|
||||
|
||||
The following demonstrates that the transaction invalidates once the timeout occurs:
|
||||
|
||||
```python
|
||||
# Create a timeout fulfillment tx
|
||||
tx_timeout_transfer = b.create_transaction(None, testuser1_pub, {'txid': tx_timeout['id'], 'cid': 0}, 'TRANSFER')
|
||||
|
||||
# Parse the timeout condition and create the corresponding fulfillment
|
||||
timeout_fulfillment = cc.Fulfillment.from_json(
|
||||
tx_timeout['transaction']['conditions'][0]['condition']['details'])
|
||||
tx_timeout_transfer['transaction']['fulfillments'][0]['fulfillment'] = timeout_fulfillment.serialize_uri()
|
||||
|
||||
# No need to sign transaction, like with hashlocks
|
||||
|
||||
# Small test to see the state change
|
||||
for i in range(time_sleep - 4):
|
||||
tx_timeout_valid = b.is_valid_transaction(tx_timeout_transfer) == tx_timeout_transfer
|
||||
seconds_to_timeout = int(float(time_expire) - float(util.timestamp()))
|
||||
print('tx_timeout valid: {} ({}s to timeout)'.format(tx_timeout_valid, seconds_to_timeout))
|
||||
sleep(1)
|
||||
```
|
||||
|
||||
If you were fast enough, you should see the following output:
|
||||
|
||||
```python
|
||||
tx_timeout valid: True (3s to timeout)
|
||||
tx_timeout valid: True (2s to timeout)
|
||||
tx_timeout valid: True (1s to timeout)
|
||||
tx_timeout valid: True (0s to timeout)
|
||||
tx_timeout valid: False (0s to timeout)
|
||||
tx_timeout valid: False (-1s to timeout)
|
||||
tx_timeout valid: False (-2s to timeout)
|
||||
tx_timeout valid: False (-3s to timeout)
|
||||
```
|
||||
|
||||
## Escrow
|
||||
|
||||
Escrow is a mechanism for conditional release of assets.
|
||||
|
||||
This means that a the assets are locked up by a trusted party until an `execute` condition is presented. In order not to tie up the assets forever, the escrow foresees an `abort` condition, which is typically an expiry time.
|
||||
|
||||
BigchainDB and cryptoconditions provides escrow out-of-the-box, without the need of a trusted party.
|
||||
|
||||
A threshold condition is used to represent the escrow, since BigchainDB transactions cannot have a _pending_ state.
|
||||
|
||||

|
||||
|
||||
The logic for switching between `execute` and `abort` conditions is conceptually simple:
|
||||
|
||||
```python
|
||||
if timeout_condition.validate(utcnow()):
|
||||
execute_fulfillment.validate(msg) == True
|
||||
abort_fulfillment.validate(msg) == False
|
||||
else:
|
||||
execute_fulfillment.validate(msg) == False
|
||||
abort_fulfillment.validate(msg) == True
|
||||
```
|
||||
|
||||
The above switch can be implemented as follows using threshold cryptoconditions:
|
||||
|
||||

|
||||
|
||||
The small circle on the threshold conditions denotes an inversion of the fulfillment:
|
||||
|
||||
```python
|
||||
inverted_fulfillment.validate(msg) == not fulfillment.validate(msg)
|
||||
```
|
||||
|
||||
An inverted input to a threshold condition is simply obtained by using negative weights.
|
||||
|
||||
__Note__: negative weights are BigchainDB-specific and not (yet) supported by the ILP standard.
|
||||
|
||||
The following code snippet shows how to create an escrow condition
|
||||
|
||||
```python
|
||||
# Retrieve the last transaction of testuser2_pub
|
||||
tx_retrieved_id = b.get_owned_ids(testuser2_pub).pop()
|
||||
|
||||
# Create a base template with the execute and abort address
|
||||
tx_escrow = b.create_transaction(testuser2_pub, [testuser2_pub, testuser1_pub], tx_retrieved_id, 'TRANSFER')
|
||||
|
||||
# Set expiry time - the execute address needs to fulfill before expiration
|
||||
time_sleep = 12
|
||||
time_expire = str(float(util.timestamp()) + time_sleep) # 12 secs from now
|
||||
|
||||
# Create the escrow and timeout condition
|
||||
condition_escrow = cc.ThresholdSha256Fulfillment(threshold=1) # OR Gate
|
||||
condition_timeout = cc.TimeoutFulfillment(expire_time=time_expire) # only valid if now() <= time_expire
|
||||
|
||||
# Create the execute branch
|
||||
condition_execute = cc.ThresholdSha256Fulfillment(threshold=2) # AND gate
|
||||
condition_execute.add_subfulfillment(cc.Ed25519Fulfillment(public_key=testuser1_pub)) # execute address
|
||||
condition_execute.add_subfulfillment(condition_timeout) # federation checks on expiry
|
||||
condition_escrow.add_subfulfillment(condition_execute)
|
||||
|
||||
# Create the abort branch
|
||||
condition_abort = cc.ThresholdSha256Fulfillment(threshold=2) # AND gate
|
||||
condition_abort.add_subfulfillment(cc.Ed25519Fulfillment(public_key=testuser2_pub)) # abort address
|
||||
condition_abort.add_subfulfillment(condition_timeout, weight=-1) # the negative weight inverts the condition
|
||||
condition_escrow.add_subfulfillment(condition_abort)
|
||||
|
||||
# Update the condition in the newly created transaction
|
||||
tx_escrow['transaction']['conditions'][0]['condition'] = {
|
||||
'details': json.loads(condition_escrow.serialize_json()),
|
||||
'uri': condition_escrow.condition.serialize_uri()
|
||||
}
|
||||
|
||||
# Conditions have been updated, so the hash needs updating
|
||||
tx_escrow['id'] = util.get_hash_data(tx_escrow)
|
||||
|
||||
# The asset needs to be signed by the current_owner
|
||||
tx_escrow_signed = b.sign_transaction(tx_escrow, testuser2_priv)
|
||||
|
||||
# Some validations
|
||||
assert b.validate_transaction(tx_escrow_signed) == tx_escrow_signed
|
||||
assert b.is_valid_transaction(tx_escrow_signed) == tx_escrow_signed
|
||||
|
||||
b.write_transaction(tx_escrow_signed)
|
||||
tx_escrow_signed
|
||||
```
|
@ -1884,6 +1884,7 @@ class TestCryptoconditions(object):
|
||||
first_input_tx = b.get_owned_ids(user_vk).pop()
|
||||
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||
|
||||
# ESCROW
|
||||
escrow_tx = b.create_transaction(user_vk, [user_vk, user2_vk], first_input_tx, 'TRANSFER')
|
||||
|
||||
time_sleep = 3
|
||||
@ -1926,12 +1927,10 @@ class TestCryptoconditions(object):
|
||||
block = b.create_block([escrow_tx_signed])
|
||||
b.write_block(block, durability='hard')
|
||||
|
||||
# create hashlock fulfillment tx
|
||||
# Retrieve the last transaction of thresholduser1_pub
|
||||
tx_retrieved_id = b.get_owned_ids(user2_vk).pop()
|
||||
|
||||
# EXECUTE
|
||||
|
||||
# Create a base template for output transaction
|
||||
escrow_tx_transfer = b.create_transaction([user_vk, user2_vk], user2_vk, tx_retrieved_id, 'TRANSFER')
|
||||
|
||||
@ -1973,7 +1972,6 @@ class TestCryptoconditions(object):
|
||||
assert b.validate_transaction(escrow_tx_transfer) == escrow_tx_transfer
|
||||
|
||||
# ABORT
|
||||
|
||||
# Create a base template for output transaction
|
||||
escrow_tx_abort = b.create_transaction([user_vk, user2_vk], user_vk, tx_retrieved_id, 'TRANSFER')
|
||||
|
||||
@ -2013,6 +2011,7 @@ class TestCryptoconditions(object):
|
||||
first_input_tx = b.get_owned_ids(user_vk).pop()
|
||||
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||
|
||||
# ESCROW
|
||||
escrow_tx = b.create_transaction(user_vk, [user_vk, user2_vk], first_input_tx, 'TRANSFER')
|
||||
|
||||
time_sleep = 3
|
||||
@ -2055,12 +2054,10 @@ class TestCryptoconditions(object):
|
||||
block = b.create_block([escrow_tx_signed])
|
||||
b.write_block(block, durability='hard')
|
||||
|
||||
# create hashlock fulfillment tx
|
||||
# Retrieve the last transaction of thresholduser1_pub
|
||||
tx_retrieved_id = b.get_owned_ids(user2_vk).pop()
|
||||
|
||||
# EXECUTE
|
||||
|
||||
# Create a base template for output transaction
|
||||
escrow_tx_transfer = b.create_transaction([user_vk, user2_vk], user2_vk, tx_retrieved_id, 'TRANSFER')
|
||||
|
||||
@ -2108,7 +2105,6 @@ class TestCryptoconditions(object):
|
||||
assert b.validate_transaction(escrow_tx_transfer) == escrow_tx_transfer
|
||||
|
||||
# ABORT
|
||||
|
||||
# Create a base template for output transaction
|
||||
escrow_tx_abort = b.create_transaction([user_vk, user2_vk], user_vk, tx_retrieved_id, 'TRANSFER')
|
||||
|
||||
@ -2124,13 +2120,13 @@ class TestCryptoconditions(object):
|
||||
escrow_tx_abort['transaction']['fulfillments'][0],
|
||||
serialized=True)
|
||||
escrow_fulfillment.subconditions = []
|
||||
# fulfill execute branch
|
||||
# do not fulfill execute branch
|
||||
fulfillment_and_execute = cc.ThresholdSha256Fulfillment(threshold=2)
|
||||
fulfillment_and_execute.add_subfulfillment(subfulfillment_user2)
|
||||
fulfillment_and_execute.add_subfulfillment(fulfillment_timeout)
|
||||
escrow_fulfillment.add_subcondition(fulfillment_and_execute.condition)
|
||||
|
||||
# do not fulfill abort branch
|
||||
# fulfill abort branch
|
||||
fulfillment_and_abort = cc.ThresholdSha256Fulfillment(threshold=2)
|
||||
subfulfillment_user.sign(escrow_tx_fulfillment_message, crypto.SigningKey(user_sk))
|
||||
fulfillment_and_abort.add_subfulfillment(subfulfillment_user)
|
||||
|
@ -106,6 +106,7 @@ sleep(8)
|
||||
|
||||
# retrieve the transaction
|
||||
tx_multisig_retrieved = b.get_transaction(tx_multisig_signed['id'])
|
||||
assert tx_multisig_retrieved is not None
|
||||
|
||||
print(json.dumps(tx_multisig_retrieved, sort_keys=True, indent=4, separators=(',', ':')))
|
||||
|
||||
@ -115,7 +116,11 @@ 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.validate_transaction(tx_multisig_transfer_signed)
|
||||
try:
|
||||
b.validate_transaction(tx_multisig_transfer_signed)
|
||||
except exceptions.InvalidSignature:
|
||||
import ipdb; ipdb.set_trace()
|
||||
b.validate_transaction(tx_multisig_transfer_signed)
|
||||
b.write_transaction(tx_multisig_transfer_signed)
|
||||
|
||||
# wait a few seconds for the asset to appear on the blockchain
|
||||
@ -151,6 +156,8 @@ b.write_transaction(tx_mimo_signed)
|
||||
|
||||
print(json.dumps(tx_mimo_signed, sort_keys=True, indent=4, separators=(',', ':')))
|
||||
|
||||
sleep(8)
|
||||
|
||||
"""
|
||||
Threshold Conditions
|
||||
"""
|
||||
@ -298,3 +305,181 @@ assert b.is_valid_transaction(hashlock_fulfill_tx) == hashlock_fulfill_tx
|
||||
|
||||
b.write_transaction(hashlock_fulfill_tx)
|
||||
print(json.dumps(hashlock_fulfill_tx, sort_keys=True, indent=4, separators=(',', ':')))
|
||||
|
||||
|
||||
"""
|
||||
Timeout Conditions
|
||||
"""
|
||||
# Create transaction template
|
||||
tx_timeout = b.create_transaction(b.me, None, None, 'CREATE')
|
||||
|
||||
# Set expiry time (12 secs from now)
|
||||
time_sleep = 12
|
||||
time_expire = str(float(util.timestamp()) + time_sleep)
|
||||
|
||||
# only valid if the server time <= time_expire
|
||||
condition_timeout = cc.TimeoutFulfillment(expire_time=time_expire)
|
||||
|
||||
# The conditions list is empty, so we need to append a new condition
|
||||
tx_timeout['transaction']['conditions'].append({
|
||||
'condition': {
|
||||
'details': json.loads(condition_timeout.serialize_json()),
|
||||
'uri': condition_timeout.condition.serialize_uri()
|
||||
},
|
||||
'cid': 0,
|
||||
'new_owners': None
|
||||
})
|
||||
|
||||
# conditions have been updated, so hash needs updating
|
||||
tx_timeout['id'] = util.get_hash_data(tx_timeout)
|
||||
|
||||
# sign transaction
|
||||
tx_timeout_signed = b.sign_transaction(tx_timeout, b.me_private)
|
||||
|
||||
b.write_transaction(tx_timeout_signed)
|
||||
print(json.dumps(tx_timeout, sort_keys=True, indent=4, separators=(',', ':')))
|
||||
sleep(8)
|
||||
|
||||
# Retrieve the transaction id of tx_timeout
|
||||
tx_timeout_id = {'txid': tx_timeout['id'], 'cid': 0}
|
||||
|
||||
# Create a template to transfer the tx_timeout
|
||||
tx_timeout_transfer = b.create_transaction(None, testuser1_pub, tx_timeout_id, 'TRANSFER')
|
||||
|
||||
# Parse the threshold cryptocondition
|
||||
timeout_fulfillment = cc.Fulfillment.from_json(
|
||||
tx_timeout['transaction']['conditions'][0]['condition']['details'])
|
||||
|
||||
tx_timeout_transfer['transaction']['fulfillments'][0]['fulfillment'] = timeout_fulfillment.serialize_uri()
|
||||
|
||||
# no need to sign transaction, like with hashlocks
|
||||
for i in range(time_sleep - 4):
|
||||
tx_timeout_valid = b.is_valid_transaction(tx_timeout_transfer) == tx_timeout_transfer
|
||||
seconds_to_timeout = int(float(time_expire) - float(util.timestamp()))
|
||||
print('tx_timeout valid: {} ({}s to timeout)'.format(tx_timeout_valid, seconds_to_timeout))
|
||||
sleep(1)
|
||||
|
||||
"""
|
||||
Escrow Conditions
|
||||
"""
|
||||
# retrieve the last transaction of testuser2
|
||||
tx_retrieved_id = b.get_owned_ids(testuser2_pub).pop()
|
||||
|
||||
# Create escrow template with the execute and abort address
|
||||
tx_escrow = b.create_transaction(testuser2_pub, [testuser2_pub, testuser1_pub], tx_retrieved_id, 'TRANSFER')
|
||||
|
||||
# Set expiry time (12 secs from now)
|
||||
time_sleep = 12
|
||||
time_expire = str(float(util.timestamp()) + time_sleep)
|
||||
|
||||
# Create escrow and timeout condition
|
||||
condition_escrow = cc.ThresholdSha256Fulfillment(threshold=1) # OR Gate
|
||||
condition_timeout = cc.TimeoutFulfillment(expire_time=time_expire) # only valid if now() <= time_expire
|
||||
|
||||
# Create execute branch
|
||||
condition_execute = cc.ThresholdSha256Fulfillment(threshold=2) # AND gate
|
||||
condition_execute.add_subfulfillment(cc.Ed25519Fulfillment(public_key=testuser1_pub)) # execute address
|
||||
condition_execute.add_subfulfillment(condition_timeout) # federation checks on expiry
|
||||
condition_escrow.add_subfulfillment(condition_execute)
|
||||
|
||||
# Create abort branch
|
||||
condition_abort = cc.ThresholdSha256Fulfillment(threshold=2) # AND gate
|
||||
condition_abort.add_subfulfillment(cc.Ed25519Fulfillment(public_key=testuser2_pub)) # abort address
|
||||
condition_abort.add_subfulfillment(condition_timeout, weight=-1) # the negative weight inverts the condition
|
||||
condition_escrow.add_subfulfillment(condition_abort)
|
||||
|
||||
# Update the condition in the newly created transaction
|
||||
tx_escrow['transaction']['conditions'][0]['condition'] = {
|
||||
'details': json.loads(condition_escrow.serialize_json()),
|
||||
'uri': condition_escrow.condition.serialize_uri()
|
||||
}
|
||||
|
||||
# conditions have been updated, so hash needs updating
|
||||
tx_escrow['id'] = util.get_hash_data(tx_escrow)
|
||||
|
||||
# sign transaction
|
||||
tx_escrow_signed = b.sign_transaction(tx_escrow, testuser2_priv)
|
||||
|
||||
# some checks
|
||||
assert b.validate_transaction(tx_escrow_signed) == tx_escrow_signed
|
||||
assert b.is_valid_transaction(tx_escrow_signed) == tx_escrow_signed
|
||||
|
||||
print(json.dumps(tx_escrow_signed, sort_keys=True, indent=4, separators=(',', ':')))
|
||||
b.write_transaction(tx_escrow_signed)
|
||||
sleep(8)
|
||||
|
||||
# Retrieve the last transaction of thresholduser1_pub
|
||||
tx_escrow_id = {'txid': tx_escrow_signed['id'], 'cid': 0}
|
||||
|
||||
# Create a base template for output transaction
|
||||
tx_escrow_execute = b.create_transaction([testuser2_pub, testuser1_pub], testuser1_pub, tx_escrow_id, 'TRANSFER')
|
||||
|
||||
# Parse the threshold cryptocondition
|
||||
escrow_fulfillment = cc.Fulfillment.from_json(
|
||||
tx_escrow['transaction']['conditions'][0]['condition']['details'])
|
||||
|
||||
subfulfillment_testuser1 = escrow_fulfillment.get_subcondition_from_vk(testuser1_pub)[0]
|
||||
subfulfillment_testuser2 = escrow_fulfillment.get_subcondition_from_vk(testuser2_pub)[0]
|
||||
subfulfillment_timeout = escrow_fulfillment.subconditions[0]['body'].subconditions[1]['body']
|
||||
|
||||
# Get the fulfillment message to sign
|
||||
tx_escrow_execute_fulfillment_message = \
|
||||
util.get_fulfillment_message(tx_escrow_execute,
|
||||
tx_escrow_execute['transaction']['fulfillments'][0],
|
||||
serialized=True)
|
||||
|
||||
escrow_fulfillment.subconditions = []
|
||||
|
||||
# fulfill execute branch
|
||||
fulfillment_execute = cc.ThresholdSha256Fulfillment(threshold=2)
|
||||
subfulfillment_testuser1.sign(tx_escrow_execute_fulfillment_message, crypto.SigningKey(testuser1_priv))
|
||||
fulfillment_execute.add_subfulfillment(subfulfillment_testuser1)
|
||||
fulfillment_execute.add_subfulfillment(subfulfillment_timeout)
|
||||
escrow_fulfillment.add_subfulfillment(fulfillment_execute)
|
||||
|
||||
# do not fulfill abort branch
|
||||
condition_abort = cc.ThresholdSha256Fulfillment(threshold=2)
|
||||
condition_abort.add_subfulfillment(subfulfillment_testuser2)
|
||||
condition_abort.add_subfulfillment(subfulfillment_timeout, weight=-1)
|
||||
escrow_fulfillment.add_subcondition(condition_abort.condition)
|
||||
|
||||
# create fulfillment and append to transaction
|
||||
tx_escrow_execute['transaction']['fulfillments'][0]['fulfillment'] = escrow_fulfillment.serialize_uri()
|
||||
|
||||
# Time has expired, hence the abort branch can redeem
|
||||
tx_escrow_abort = b.create_transaction([testuser2_pub, testuser1_pub], testuser2_pub, tx_escrow_id, 'TRANSFER')
|
||||
|
||||
# Parse the threshold cryptocondition
|
||||
escrow_fulfillment = cc.Fulfillment.from_json(
|
||||
tx_escrow['transaction']['conditions'][0]['condition']['details'])
|
||||
|
||||
subfulfillment_testuser1 = escrow_fulfillment.get_subcondition_from_vk(testuser1_pub)[0]
|
||||
subfulfillment_testuser2 = escrow_fulfillment.get_subcondition_from_vk(testuser2_pub)[0]
|
||||
subfulfillment_timeout = escrow_fulfillment.subconditions[0]['body'].subconditions[1]['body']
|
||||
|
||||
tx_escrow_abort_fulfillment_message = \
|
||||
util.get_fulfillment_message(tx_escrow_abort,
|
||||
tx_escrow_abort['transaction']['fulfillments'][0],
|
||||
serialized=True)
|
||||
escrow_fulfillment.subconditions = []
|
||||
|
||||
# Do not fulfill execute branch
|
||||
condition_execute = cc.ThresholdSha256Fulfillment(threshold=2)
|
||||
condition_execute.add_subfulfillment(subfulfillment_testuser1)
|
||||
condition_execute.add_subfulfillment(subfulfillment_timeout)
|
||||
escrow_fulfillment.add_subcondition(condition_execute.condition)
|
||||
|
||||
# Fulfill abort branch
|
||||
fulfillment_abort = cc.ThresholdSha256Fulfillment(threshold=2)
|
||||
subfulfillment_testuser2.sign(tx_escrow_abort_fulfillment_message, crypto.SigningKey(testuser2_priv))
|
||||
fulfillment_abort.add_subfulfillment(subfulfillment_testuser2)
|
||||
fulfillment_abort.add_subfulfillment(subfulfillment_timeout, weight=-1)
|
||||
escrow_fulfillment.add_subfulfillment(fulfillment_abort)
|
||||
|
||||
tx_escrow_abort['transaction']['fulfillments'][0]['fulfillment'] = escrow_fulfillment.serialize_uri()
|
||||
|
||||
for i in range(time_sleep - 4):
|
||||
valid_execute = b.is_valid_transaction(tx_escrow_execute) == tx_escrow_execute
|
||||
valid_abort = b.is_valid_transaction(tx_escrow_abort) == tx_escrow_abort
|
||||
print('execute: {} - abort {}'.format(valid_execute, valid_abort))
|
||||
sleep(1)
|
||||
|
Loading…
x
Reference in New Issue
Block a user