mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Merge branch 'master' into core/193/invalid-block-backlog
This commit is contained in:
commit
41328b3255
23
CHANGELOG.md
23
CHANGELOG.md
@ -14,6 +14,29 @@ For reference, the possible headings are:
|
|||||||
* **External Contributors** to list contributors outside of ascribe GmbH.
|
* **External Contributors** to list contributors outside of ascribe GmbH.
|
||||||
|
|
||||||
|
|
||||||
|
## [0.3.0] - 2016-05-03
|
||||||
|
Tag name: v0.3.0
|
||||||
|
= commit:
|
||||||
|
committed:
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Crypto-conditions specs according to the Interledger protocol: [Pull Request #174](https://github.com/bigchaindb/bigchaindb/pull/174)
|
||||||
|
- Added support for anonymous hashlocked conditions and fulfillments: [Pull Request #211](https://github.com/bigchaindb/bigchaindb/pull/211)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Several improvements to the aws deployment scripts: [Pull Request #227](https://github.com/bigchaindb/bigchaindb/pull/227)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Bug related to block validation: [Pull Request #233](https://github.com/bigchaindb/bigchaindb/pull/233)
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
This release completely refactored the structure of the transactions and broke compatibility with older versions
|
||||||
|
of BigchainDB. The refactor of the transactions was made in order to add support for multiple inputs/outputs and
|
||||||
|
the crypto-conditions specs from the Interledger protocol.
|
||||||
|
|
||||||
|
We also updated the rethinkdb python drivers so you need to upgrade to rethinkdb v2.3+
|
||||||
|
|
||||||
|
|
||||||
## [0.2.0] - 2016-04-26
|
## [0.2.0] - 2016-04-26
|
||||||
Tag name: v0.2.0
|
Tag name: v0.2.0
|
||||||
= commit: 0c4a2b380aabdcf50fa2d7fb351c290aaedc3db7
|
= commit: 0c4a2b380aabdcf50fa2d7fb351c290aaedc3db7
|
||||||
|
@ -43,6 +43,16 @@ my_string = 'This is a very long string, so long that it will not fit into just
|
|||||||
|
|
||||||
It seems the preference is for slashes, but using parentheses is okay too. (There are good arguments either way. Arguing about it seems like a waste of time.)
|
It seems the preference is for slashes, but using parentheses is okay too. (There are good arguments either way. Arguing about it seems like a waste of time.)
|
||||||
|
|
||||||
|
### How to Format Long import Statements
|
||||||
|
|
||||||
|
If you need to `import` lots of names from a module or package, and they won't all fit in one line (without making the line too long), then use parentheses to spread the names across multiple lines, like so:
|
||||||
|
```python
|
||||||
|
from Tkinter import (Tk, Frame, Button, Entry, Canvas, Text,
|
||||||
|
LEFT, DISABLED, NORMAL, RIDGE, END)
|
||||||
|
```
|
||||||
|
|
||||||
|
For the rationale, see [PEP 328](https://www.python.org/dev/peps/pep-0328/#rationale-for-parentheses).
|
||||||
|
|
||||||
### Using the % operator or `format()` to Format Strings
|
### Using the % operator or `format()` to Format Strings
|
||||||
|
|
||||||
Given the choice:
|
Given the choice:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
[](https://pypi.python.org/pypi/BigchainDB)
|
[](https://pypi.python.org/pypi/BigchainDB)
|
||||||
[](https://travis-ci.org/bigchaindb/bigchaindb)
|
[](https://travis-ci.org/bigchaindb/bigchaindb)
|
||||||
[](https://codecov.io/github/bigchaindb/bigchaindb?branch=master)
|
[](https://codecov.io/github/bigchaindb/bigchaindb?branch=master)
|
||||||
[](https://bigchaindb.readthedocs.org/en/stable/)
|
[](https://bigchaindb.readthedocs.org/en/latest/)
|
||||||
|
|
||||||
|
|
||||||
# BigchainDB
|
# BigchainDB
|
||||||
|
@ -176,7 +176,6 @@ class BaseConsensusRules(AbstractConsensusRules):
|
|||||||
|
|
||||||
return transaction
|
return transaction
|
||||||
|
|
||||||
# TODO: Unsure if a bigchain parameter is really necessary here?
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_block(bigchain, block):
|
def validate_block(bigchain, block):
|
||||||
"""Validate a block.
|
"""Validate a block.
|
||||||
@ -198,6 +197,15 @@ class BaseConsensusRules(AbstractConsensusRules):
|
|||||||
if calculated_hash != block['id']:
|
if calculated_hash != block['id']:
|
||||||
raise exceptions.InvalidHash()
|
raise exceptions.InvalidHash()
|
||||||
|
|
||||||
|
# Check if the block was created by a federation node
|
||||||
|
if block['block']['node_pubkey'] not in (bigchain.federation_nodes + [bigchain.me]):
|
||||||
|
raise exceptions.OperationError('Only federation nodes can create blocks')
|
||||||
|
|
||||||
|
# Check if block signature is valid
|
||||||
|
verifying_key = crypto.VerifyingKey(block['block']['node_pubkey'])
|
||||||
|
if not verifying_key.verify(util.serialize(block['block']), block['signature']):
|
||||||
|
raise exceptions.InvalidSignature('Invalid block signature')
|
||||||
|
|
||||||
return block
|
return block
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -203,11 +203,20 @@ def create_tx(current_owners, new_owners, inputs, operation, payload=None):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
# validate arguments (owners and inputs should be lists)
|
# validate arguments (owners and inputs should be lists or None)
|
||||||
|
|
||||||
|
# The None case appears on fulfilling a hashlock
|
||||||
|
if current_owners is None:
|
||||||
|
current_owners = []
|
||||||
if not isinstance(current_owners, list):
|
if not isinstance(current_owners, list):
|
||||||
current_owners = [current_owners]
|
current_owners = [current_owners]
|
||||||
|
|
||||||
|
# The None case appears on assigning a hashlock
|
||||||
|
if new_owners is None:
|
||||||
|
new_owners = []
|
||||||
if not isinstance(new_owners, list):
|
if not isinstance(new_owners, list):
|
||||||
new_owners = [new_owners]
|
new_owners = [new_owners]
|
||||||
|
|
||||||
if not isinstance(inputs, list):
|
if not isinstance(inputs, list):
|
||||||
inputs = [inputs]
|
inputs = [inputs]
|
||||||
|
|
||||||
@ -247,20 +256,30 @@ def create_tx(current_owners, new_owners, inputs, operation, payload=None):
|
|||||||
# handle outputs
|
# handle outputs
|
||||||
conditions = []
|
conditions = []
|
||||||
for fulfillment in fulfillments:
|
for fulfillment in fulfillments:
|
||||||
|
|
||||||
|
# threshold condition
|
||||||
if len(new_owners) > 1:
|
if len(new_owners) > 1:
|
||||||
condition = cc.ThresholdSha256Fulfillment(threshold=len(new_owners))
|
condition = cc.ThresholdSha256Fulfillment(threshold=len(new_owners))
|
||||||
for new_owner in new_owners:
|
for new_owner in new_owners:
|
||||||
condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=new_owner))
|
condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=new_owner))
|
||||||
|
|
||||||
|
# simple signature condition
|
||||||
elif len(new_owners) == 1:
|
elif len(new_owners) == 1:
|
||||||
condition = cc.Ed25519Fulfillment(public_key=new_owners[0])
|
condition = cc.Ed25519Fulfillment(public_key=new_owners[0])
|
||||||
conditions.append({
|
|
||||||
'new_owners': new_owners,
|
# to be added later (hashlock conditions)
|
||||||
'condition': {
|
else:
|
||||||
'details': json.loads(condition.serialize_json()),
|
condition = None
|
||||||
'uri': condition.condition.serialize_uri()
|
|
||||||
},
|
if condition:
|
||||||
'cid': fulfillment['fid']
|
conditions.append({
|
||||||
})
|
'new_owners': new_owners,
|
||||||
|
'condition': {
|
||||||
|
'details': json.loads(condition.serialize_json()),
|
||||||
|
'uri': condition.condition.serialize_uri()
|
||||||
|
},
|
||||||
|
'cid': fulfillment['fid']
|
||||||
|
})
|
||||||
|
|
||||||
tx = {
|
tx = {
|
||||||
'fulfillments': fulfillments,
|
'fulfillments': fulfillments,
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
__version__ = '0.2.0'
|
__version__ = '0.3.0'
|
||||||
__short_version__ = '0.2'
|
__short_version__ = '0.3'
|
@ -26,6 +26,7 @@ coverage:
|
|||||||
- "deploy-cluster-aws/*"
|
- "deploy-cluster-aws/*"
|
||||||
- "docs/*"
|
- "docs/*"
|
||||||
- "tests/*"
|
- "tests/*"
|
||||||
|
- "bigchaindb/version.py"
|
||||||
|
|
||||||
comment:
|
comment:
|
||||||
# @stevepeak (from codecov.io) suggested we change 'suggestions' to 'uncovered'
|
# @stevepeak (from codecov.io) suggested we change 'suggestions' to 'uncovered'
|
||||||
|
@ -746,3 +746,142 @@ threshold_tx_transfer
|
|||||||
"version":1
|
"version":1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Hash-locked Conditions
|
||||||
|
|
||||||
|
By creating a hash of a difficult-to-guess 256-bit random or pseudo-random integer it is possible to create a condition which the creator can trivially fulfill by publishing the random value. However, for anyone else, the condition is cryptographically hard to fulfill, because they would have to find a preimage for the given condition hash.
|
||||||
|
|
||||||
|
One possible usecase might be to redeem a digital voucher when given a secret (voucher code).
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Create a hash-locked asset without any new_owners
|
||||||
|
hashlock_tx = b.create_transaction(b.me, None, None, 'CREATE')
|
||||||
|
|
||||||
|
# Define a secret that will be hashed - fulfillments need to guess the secret
|
||||||
|
secret = b'much secret! wow!'
|
||||||
|
first_tx_condition = cc.PreimageSha256Fulfillment(preimage=secret)
|
||||||
|
|
||||||
|
# The conditions list is empty, so we need to append a new condition
|
||||||
|
hashlock_tx['transaction']['conditions'].append({
|
||||||
|
'condition': {
|
||||||
|
'uri': first_tx_condition.condition.serialize_uri()
|
||||||
|
},
|
||||||
|
'cid': 0,
|
||||||
|
'new_owners': None
|
||||||
|
})
|
||||||
|
|
||||||
|
# Conditions have been updated, so hash needs updating
|
||||||
|
hashlock_tx['id'] = util.get_hash_data(hashlock_tx)
|
||||||
|
|
||||||
|
# The asset needs to be signed by the current_owner
|
||||||
|
hashlock_tx_signed = b.sign_transaction(hashlock_tx, b.me_private)
|
||||||
|
|
||||||
|
# Some validations
|
||||||
|
assert b.validate_transaction(hashlock_tx_signed) == hashlock_tx_signed
|
||||||
|
assert b.is_valid_transaction(hashlock_tx_signed) == hashlock_tx_signed
|
||||||
|
|
||||||
|
b.write_transaction(hashlock_tx_signed)
|
||||||
|
hashlock_tx_signed
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"assignee":"FmLm6MxCABc8TsiZKdeYaZKo5yZWMM6Vty7Q1B6EgcP2",
|
||||||
|
"id":"604c520244b7ff63604527baf269e0cbfb887122f503703120fd347d6b99a237",
|
||||||
|
"transaction":{
|
||||||
|
"conditions":[
|
||||||
|
{
|
||||||
|
"cid":0,
|
||||||
|
"condition":{
|
||||||
|
"uri":"cc:0:3:nsW2IiYgk9EUtsg4uBe3pBnOgRoAEX2IIsPgjqZz47U:17"
|
||||||
|
},
|
||||||
|
"new_owners":None
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"data":None,
|
||||||
|
"fulfillments":[
|
||||||
|
{
|
||||||
|
"current_owners":[
|
||||||
|
"FmLm6MxCABc8TsiZKdeYaZKo5yZWMM6Vty7Q1B6EgcP2"
|
||||||
|
],
|
||||||
|
"fid":0,
|
||||||
|
"fulfillment":"cf:4:21-D-LfNhIQhvY5914ArFTUGpgPKc7EVC1ZtJqqOTHGx1p9FuRr9tRfkbdqtX2MZWh7sRVUmMnwp7I1-xZbCnCkeADf69IwDHbZvNS6aTr1CpekREsV9ZG8m_wjlZiUN",
|
||||||
|
"input":None
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"operation":"CREATE",
|
||||||
|
"timestamp":"1461250387.910102"
|
||||||
|
},
|
||||||
|
"version":1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In order to redeem the asset, one needs to create a fulfillment the correct secret as a preimage:
|
||||||
|
|
||||||
|
```python
|
||||||
|
hashlockuser_priv, hashlockuser_pub = crypto.generate_key_pair()
|
||||||
|
|
||||||
|
# create hashlock fulfillment tx
|
||||||
|
hashlock_fulfill_tx = b.create_transaction(None, hashlockuser_pub, {'txid': hashlock_tx['id'], 'cid': 0}, 'TRANSFER')
|
||||||
|
|
||||||
|
# provide a wrong secret
|
||||||
|
hashlock_fulfill_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=b'')
|
||||||
|
hashlock_fulfill_tx['transaction']['fulfillments'][0]['fulfillment'] = \
|
||||||
|
hashlock_fulfill_tx_fulfillment.serialize_uri()
|
||||||
|
|
||||||
|
assert b.is_valid_transaction(hashlock_fulfill_tx) == False
|
||||||
|
|
||||||
|
# provide the right secret
|
||||||
|
hashlock_fulfill_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=secret)
|
||||||
|
hashlock_fulfill_tx['transaction']['fulfillments'][0]['fulfillment'] = \
|
||||||
|
hashlock_fulfill_tx_fulfillment.serialize_uri()
|
||||||
|
|
||||||
|
assert b.validate_transaction(hashlock_fulfill_tx) == hashlock_fulfill_tx
|
||||||
|
assert b.is_valid_transaction(hashlock_fulfill_tx) == hashlock_fulfill_tx
|
||||||
|
|
||||||
|
b.write_transaction(hashlock_fulfill_tx)
|
||||||
|
hashlock_fulfill_tx
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"assignee":"FmLm6MxCABc8TsiZKdeYaZKo5yZWMM6Vty7Q1B6EgcP2",
|
||||||
|
"id":"fe6871bf3ca62eb61c52c5555cec2e07af51df817723f0cb76e5cf6248f449d2",
|
||||||
|
"transaction":{
|
||||||
|
"conditions":[
|
||||||
|
{
|
||||||
|
"cid":0,
|
||||||
|
"condition":{
|
||||||
|
"details":{
|
||||||
|
"bitmask":32,
|
||||||
|
"public_key":"EiqCKxnBCmmNb83qyGch48tULK9RLaEt4xFA43UVCVDb",
|
||||||
|
"signature":None,
|
||||||
|
"type":"fulfillment",
|
||||||
|
"type_id":4
|
||||||
|
},
|
||||||
|
"uri":"cc:4:20:y9884Md2YI_wdnGSTJGhwvFaNsKLe8sqwimqk-2JLSI:96"
|
||||||
|
},
|
||||||
|
"new_owners":[
|
||||||
|
"EiqCKxnBCmmNb83qyGch48tULK9RLaEt4xFA43UVCVDb"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"data":None,
|
||||||
|
"fulfillments":[
|
||||||
|
{
|
||||||
|
"current_owners":[],
|
||||||
|
"fid":0,
|
||||||
|
"fulfillment":"cf:0:bXVjaCBzZWNyZXQhIHdvdyE",
|
||||||
|
"input":{
|
||||||
|
"cid":0,
|
||||||
|
"txid":"604c520244b7ff63604527baf269e0cbfb887122f503703120fd347d6b99a237"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"operation":"TRANSFER",
|
||||||
|
"timestamp":"1461250397.944510"
|
||||||
|
},
|
||||||
|
"version":1
|
||||||
|
}
|
||||||
|
```
|
@ -433,6 +433,37 @@ class TestBlockValidation(object):
|
|||||||
assert block == b.validate_block(block)
|
assert block == b.validate_block(block)
|
||||||
assert b.is_valid_block(block)
|
assert b.is_valid_block(block)
|
||||||
|
|
||||||
|
def test_invalid_signature(self, b):
|
||||||
|
# create a valid block
|
||||||
|
block = b.create_block([])
|
||||||
|
|
||||||
|
# replace the block signature with an invalid one
|
||||||
|
block['signature'] = crypto.SigningKey(b.me_private).sign(b'wrongdata')
|
||||||
|
|
||||||
|
# check that validate_block raises an InvalidSignature exception
|
||||||
|
with pytest.raises(exceptions.InvalidSignature):
|
||||||
|
b.validate_block(block)
|
||||||
|
|
||||||
|
def test_invalid_node_pubkey(self, b):
|
||||||
|
# blocks can only be created by a federation node
|
||||||
|
# create a valid block
|
||||||
|
block = b.create_block([])
|
||||||
|
|
||||||
|
# create some temp keys
|
||||||
|
tmp_sk, tmp_vk = crypto.generate_key_pair()
|
||||||
|
|
||||||
|
# change the block node_pubkey
|
||||||
|
block['block']['node_pubkey'] = tmp_vk
|
||||||
|
|
||||||
|
# just to make sure lets re-hash the block and create a valid signature
|
||||||
|
# from a non federation node
|
||||||
|
block['id'] = crypto.hash_data(util.serialize(block['block']))
|
||||||
|
block['signature'] = crypto.SigningKey(tmp_sk).sign(util.serialize(block['block']))
|
||||||
|
|
||||||
|
# check that validate_block raises an OperationError
|
||||||
|
with pytest.raises(exceptions.OperationError):
|
||||||
|
b.validate_block(block)
|
||||||
|
|
||||||
|
|
||||||
class TestBigchainVoter(object):
|
class TestBigchainVoter(object):
|
||||||
def test_valid_block_voting(self, b):
|
def test_valid_block_voting(self, b):
|
||||||
@ -1544,6 +1575,136 @@ class TestCryptoconditions(object):
|
|||||||
|
|
||||||
assert b.verify_signature(tx_transfer_signed) is True
|
assert b.verify_signature(tx_transfer_signed) is True
|
||||||
|
|
||||||
|
def test_create_asset_with_hashlock_condition(self, b):
|
||||||
|
hashlock_tx = b.create_transaction(b.me, None, None, 'CREATE')
|
||||||
|
|
||||||
|
secret = b'much secret! wow!'
|
||||||
|
first_tx_condition = cc.PreimageSha256Fulfillment(preimage=secret)
|
||||||
|
|
||||||
|
hashlock_tx['transaction']['conditions'].append({
|
||||||
|
'condition': {
|
||||||
|
'details': json.loads(first_tx_condition.serialize_json()),
|
||||||
|
'uri': first_tx_condition.condition.serialize_uri()
|
||||||
|
},
|
||||||
|
'cid': 0,
|
||||||
|
'new_owners': None
|
||||||
|
})
|
||||||
|
# conditions have been updated, so hash needs updating
|
||||||
|
hashlock_tx['id'] = util.get_hash_data(hashlock_tx)
|
||||||
|
|
||||||
|
hashlock_tx_signed = b.sign_transaction(hashlock_tx, b.me_private)
|
||||||
|
|
||||||
|
assert b.validate_transaction(hashlock_tx_signed) == hashlock_tx_signed
|
||||||
|
assert b.is_valid_transaction(hashlock_tx_signed) == hashlock_tx_signed
|
||||||
|
|
||||||
|
b.write_transaction(hashlock_tx_signed)
|
||||||
|
|
||||||
|
# create and write block to bigchain
|
||||||
|
block = b.create_block([hashlock_tx_signed])
|
||||||
|
b.write_block(block, durability='hard')
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('inputs')
|
||||||
|
def test_transfer_asset_with_hashlock_condition(self, b, user_vk, user_sk):
|
||||||
|
first_input_tx = b.get_owned_ids(user_vk).pop()
|
||||||
|
|
||||||
|
hashlock_tx = b.create_transaction(user_vk, None, first_input_tx, 'TRANSFER')
|
||||||
|
|
||||||
|
secret = b'much secret! wow!'
|
||||||
|
first_tx_condition = cc.PreimageSha256Fulfillment(preimage=secret)
|
||||||
|
|
||||||
|
hashlock_tx['transaction']['conditions'].append({
|
||||||
|
'condition': {
|
||||||
|
'details': json.loads(first_tx_condition.serialize_json()),
|
||||||
|
'uri': first_tx_condition.condition.serialize_uri()
|
||||||
|
},
|
||||||
|
'cid': 0,
|
||||||
|
'new_owners': None
|
||||||
|
})
|
||||||
|
# conditions have been updated, so hash needs updating
|
||||||
|
hashlock_tx['id'] = util.get_hash_data(hashlock_tx)
|
||||||
|
|
||||||
|
hashlock_tx_signed = b.sign_transaction(hashlock_tx, user_sk)
|
||||||
|
|
||||||
|
assert b.validate_transaction(hashlock_tx_signed) == hashlock_tx_signed
|
||||||
|
assert b.is_valid_transaction(hashlock_tx_signed) == hashlock_tx_signed
|
||||||
|
assert len(b.get_owned_ids(user_vk)) == 1
|
||||||
|
|
||||||
|
b.write_transaction(hashlock_tx_signed)
|
||||||
|
|
||||||
|
# create and write block to bigchain
|
||||||
|
block = b.create_block([hashlock_tx_signed])
|
||||||
|
b.write_block(block, durability='hard')
|
||||||
|
|
||||||
|
assert len(b.get_owned_ids(user_vk)) == 0
|
||||||
|
|
||||||
|
def test_create_and_fulfill_asset_with_hashlock_condition(self, b, user_vk):
|
||||||
|
hashlock_tx = b.create_transaction(b.me, None, None, 'CREATE')
|
||||||
|
|
||||||
|
secret = b'much secret! wow!'
|
||||||
|
first_tx_condition = cc.PreimageSha256Fulfillment(preimage=secret)
|
||||||
|
|
||||||
|
hashlock_tx['transaction']['conditions'].append({
|
||||||
|
'condition': {
|
||||||
|
'details': json.loads(first_tx_condition.serialize_json()),
|
||||||
|
'uri': first_tx_condition.condition.serialize_uri()
|
||||||
|
},
|
||||||
|
'cid': 0,
|
||||||
|
'new_owners': None
|
||||||
|
})
|
||||||
|
# conditions have been updated, so hash needs updating
|
||||||
|
hashlock_tx['id'] = util.get_hash_data(hashlock_tx)
|
||||||
|
|
||||||
|
hashlock_tx_signed = b.sign_transaction(hashlock_tx, b.me_private)
|
||||||
|
|
||||||
|
assert b.validate_transaction(hashlock_tx_signed) == hashlock_tx_signed
|
||||||
|
assert b.is_valid_transaction(hashlock_tx_signed) == hashlock_tx_signed
|
||||||
|
|
||||||
|
b.write_transaction(hashlock_tx_signed)
|
||||||
|
|
||||||
|
# create and write block to bigchain
|
||||||
|
block = b.create_block([hashlock_tx_signed])
|
||||||
|
b.write_block(block, durability='hard')
|
||||||
|
|
||||||
|
assert len(b.get_owned_ids(b.me)) == 0
|
||||||
|
|
||||||
|
# create hashlock fulfillment tx
|
||||||
|
hashlock_fulfill_tx = b.create_transaction(None, user_vk, {'txid': hashlock_tx['id'], 'cid': 0}, 'TRANSFER')
|
||||||
|
|
||||||
|
hashlock_fulfill_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=b'')
|
||||||
|
hashlock_fulfill_tx['transaction']['fulfillments'][0]['fulfillment'] = \
|
||||||
|
hashlock_fulfill_tx_fulfillment.serialize_uri()
|
||||||
|
|
||||||
|
with pytest.raises(exceptions.InvalidSignature):
|
||||||
|
b.validate_transaction(hashlock_fulfill_tx)
|
||||||
|
assert b.is_valid_transaction(hashlock_fulfill_tx) == False
|
||||||
|
|
||||||
|
hashlock_fulfill_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=secret)
|
||||||
|
hashlock_fulfill_tx['transaction']['fulfillments'][0]['fulfillment'] = \
|
||||||
|
hashlock_fulfill_tx_fulfillment.serialize_uri()
|
||||||
|
|
||||||
|
assert b.validate_transaction(hashlock_fulfill_tx) == hashlock_fulfill_tx
|
||||||
|
assert b.is_valid_transaction(hashlock_fulfill_tx) == hashlock_fulfill_tx
|
||||||
|
|
||||||
|
b.write_transaction(hashlock_fulfill_tx)
|
||||||
|
|
||||||
|
# create and write block to bigchain
|
||||||
|
block = b.create_block([hashlock_fulfill_tx])
|
||||||
|
b.write_block(block, durability='hard')
|
||||||
|
|
||||||
|
assert len(b.get_owned_ids(b.me)) == 0
|
||||||
|
assert len(b.get_owned_ids(user_vk)) == 1
|
||||||
|
|
||||||
|
# try doublespending
|
||||||
|
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||||
|
hashlock_doublespend_tx = b.create_transaction(None, user2_vk, {'txid': hashlock_tx['id'], 'cid': 0}, 'TRANSFER')
|
||||||
|
|
||||||
|
hashlock_doublespend_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=secret)
|
||||||
|
hashlock_doublespend_tx['transaction']['fulfillments'][0]['fulfillment'] = \
|
||||||
|
hashlock_doublespend_tx_fulfillment.serialize_uri()
|
||||||
|
|
||||||
|
with pytest.raises(exceptions.DoubleSpend):
|
||||||
|
b.validate_transaction(hashlock_doublespend_tx)
|
||||||
|
|
||||||
def test_get_subcondition_from_vk(self, b, user_sk, user_vk):
|
def test_get_subcondition_from_vk(self, b, user_sk, user_vk):
|
||||||
user2_sk, user2_vk = crypto.generate_key_pair()
|
user2_sk, user2_vk = crypto.generate_key_pair()
|
||||||
user3_sk, user3_vk = crypto.generate_key_pair()
|
user3_sk, user3_vk = crypto.generate_key_pair()
|
||||||
|
@ -233,4 +233,60 @@ b.write_transaction(threshold_tx_transfer)
|
|||||||
|
|
||||||
print(json.dumps(threshold_tx_transfer, sort_keys=True, indent=4, separators=(',', ':')))
|
print(json.dumps(threshold_tx_transfer, sort_keys=True, indent=4, separators=(',', ':')))
|
||||||
|
|
||||||
|
"""
|
||||||
|
Hashlocked Conditions
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Create a hash-locked asset without any new_owners
|
||||||
|
hashlock_tx = b.create_transaction(b.me, None, None, 'CREATE')
|
||||||
|
|
||||||
|
# Define a secret that will be hashed - fulfillments need to guess the secret
|
||||||
|
secret = b'much secret! wow!'
|
||||||
|
first_tx_condition = cc.PreimageSha256Fulfillment(preimage=secret)
|
||||||
|
|
||||||
|
# The conditions list is empty, so we need to append a new condition
|
||||||
|
hashlock_tx['transaction']['conditions'].append({
|
||||||
|
'condition': {
|
||||||
|
'uri': first_tx_condition.condition.serialize_uri()
|
||||||
|
},
|
||||||
|
'cid': 0,
|
||||||
|
'new_owners': None
|
||||||
|
})
|
||||||
|
|
||||||
|
# Conditions have been updated, so hash needs updating
|
||||||
|
hashlock_tx['id'] = util.get_hash_data(hashlock_tx)
|
||||||
|
|
||||||
|
# The asset needs to be signed by the current_owner
|
||||||
|
hashlock_tx_signed = b.sign_transaction(hashlock_tx, b.me_private)
|
||||||
|
|
||||||
|
# Some validations
|
||||||
|
assert b.validate_transaction(hashlock_tx_signed) == hashlock_tx_signed
|
||||||
|
assert b.is_valid_transaction(hashlock_tx_signed) == hashlock_tx_signed
|
||||||
|
|
||||||
|
b.write_transaction(hashlock_tx_signed)
|
||||||
|
print(json.dumps(hashlock_tx_signed, sort_keys=True, indent=4, separators=(',', ':')))
|
||||||
|
|
||||||
|
sleep(10)
|
||||||
|
|
||||||
|
hashlockuser_priv, hashlockuser_pub = crypto.generate_key_pair()
|
||||||
|
|
||||||
|
# create hashlock fulfillment tx
|
||||||
|
hashlock_fulfill_tx = b.create_transaction(None, hashlockuser_priv, {'txid': hashlock_tx['id'], 'cid': 0}, 'TRANSFER')
|
||||||
|
|
||||||
|
# try a wrong secret
|
||||||
|
hashlock_fulfill_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=b'')
|
||||||
|
hashlock_fulfill_tx['transaction']['fulfillments'][0]['fulfillment'] = \
|
||||||
|
hashlock_fulfill_tx_fulfillment.serialize_uri()
|
||||||
|
|
||||||
|
assert b.is_valid_transaction(hashlock_fulfill_tx) == False
|
||||||
|
|
||||||
|
# provide the right secret
|
||||||
|
hashlock_fulfill_tx_fulfillment = cc.PreimageSha256Fulfillment(preimage=secret)
|
||||||
|
hashlock_fulfill_tx['transaction']['fulfillments'][0]['fulfillment'] = \
|
||||||
|
hashlock_fulfill_tx_fulfillment.serialize_uri()
|
||||||
|
|
||||||
|
assert b.validate_transaction(hashlock_fulfill_tx) == hashlock_fulfill_tx
|
||||||
|
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=(',', ':')))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user