mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-06-26 11:16:44 +02:00
Merge branch 'master' into more-ways-to-add-tx-to-backlog
This commit is contained in:
commit
fad0be47c1
|
@ -92,9 +92,12 @@ def run_gather_metrics(args):
|
|||
|
||||
num_transactions_received += block_num_transactions
|
||||
elapsed_time = time_now - initial_time
|
||||
elapsed_time = elapsed_time if elapsed_time != 0 else 1
|
||||
percent_complete = round((num_transactions_received / num_transactions) * 100)
|
||||
transactions_per_second = round(num_transactions_received / elapsed_time)
|
||||
|
||||
if elapsed_time != 0:
|
||||
transactions_per_second = round(num_transactions_received / elapsed_time)
|
||||
else:
|
||||
transactions_per_second = float('nan')
|
||||
|
||||
logger.info('\t{:<20} {:<20} {:<20} {:<20}'.format(time_now, block_num_transactions,
|
||||
transactions_per_second, percent_complete))
|
||||
|
@ -103,9 +106,9 @@ def run_gather_metrics(args):
|
|||
break
|
||||
except KeyboardInterrupt:
|
||||
logger.info('Interrupted. Exiting early...')
|
||||
|
||||
# close files
|
||||
csv_file.close()
|
||||
finally:
|
||||
# close files
|
||||
csv_file.close()
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
@ -7,6 +7,7 @@ import rethinkdb as r
|
|||
import bigchaindb
|
||||
from bigchaindb import Bigchain
|
||||
from bigchaindb.monitor import Monitor
|
||||
from bigchaindb.util import ProcessGroup
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -180,7 +181,9 @@ class Block(object):
|
|||
# add results to the queue
|
||||
for result in initial_results:
|
||||
q_initial.put(result)
|
||||
q_initial.put('stop')
|
||||
|
||||
for i in range(mp.cpu_count()):
|
||||
q_initial.put('stop')
|
||||
|
||||
return q_initial
|
||||
|
||||
|
@ -203,17 +206,21 @@ class Block(object):
|
|||
self._start()
|
||||
logger.info('exiting block module...')
|
||||
|
||||
def kill(self):
|
||||
for i in range(mp.cpu_count()):
|
||||
self.q_new_transaction.put('stop')
|
||||
|
||||
def _start(self):
|
||||
"""
|
||||
Initialize, spawn, and start the processes
|
||||
"""
|
||||
|
||||
# initialize the processes
|
||||
p_filter = mp.Process(name='filter_transactions', target=self.filter_by_assignee)
|
||||
p_validate = mp.Process(name='validate_transactions', target=self.validate_transactions)
|
||||
p_blocks = mp.Process(name='create_blocks', target=self.create_blocks)
|
||||
p_write = mp.Process(name='write_blocks', target=self.write_blocks)
|
||||
p_delete = mp.Process(name='delete_transactions', target=self.delete_transactions)
|
||||
p_filter = ProcessGroup(name='filter_transactions', target=self.filter_by_assignee)
|
||||
p_validate = ProcessGroup(name='validate_transactions', target=self.validate_transactions)
|
||||
p_blocks = ProcessGroup(name='create_blocks', target=self.create_blocks)
|
||||
p_write = ProcessGroup(name='write_blocks', target=self.write_blocks)
|
||||
p_delete = ProcessGroup(name='delete_transactions', target=self.delete_transactions)
|
||||
|
||||
# start the processes
|
||||
p_filter.start()
|
||||
|
@ -222,9 +229,3 @@ class Block(object):
|
|||
p_write.start()
|
||||
p_delete.start()
|
||||
|
||||
# join processes
|
||||
p_filter.join()
|
||||
p_validate.join()
|
||||
p_blocks.join()
|
||||
p_write.join()
|
||||
p_delete.join()
|
||||
|
|
|
@ -16,6 +16,7 @@ import copy
|
|||
import json
|
||||
import logging
|
||||
import collections
|
||||
from functools import lru_cache
|
||||
|
||||
from pkg_resources import iter_entry_points, ResolutionError
|
||||
|
||||
|
@ -218,6 +219,7 @@ def autoconfigure(filename=None, config=None, force=False):
|
|||
set_config(newconfig) # sets bigchaindb.config
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def load_consensus_plugin(name=None):
|
||||
"""Find and load the chosen consensus plugin.
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ class AbstractConsensusRules(metaclass=ABCMeta):
|
|||
All methods listed below must be implemented.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def validate_transaction(bigchain, transaction):
|
||||
"""Validate a transaction.
|
||||
|
@ -31,8 +32,8 @@ class AbstractConsensusRules(metaclass=ABCMeta):
|
|||
Descriptive exceptions indicating the reason the transaction failed.
|
||||
See the `exceptions` module for bigchain-native error classes.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def validate_block(bigchain, block):
|
||||
"""Validate a block.
|
||||
|
@ -49,8 +50,8 @@ class AbstractConsensusRules(metaclass=ABCMeta):
|
|||
Descriptive exceptions indicating the reason the block failed.
|
||||
See the `exceptions` module for bigchain-native error classes.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def create_transaction(*args, **kwargs):
|
||||
"""Create a new transaction.
|
||||
|
@ -61,8 +62,8 @@ class AbstractConsensusRules(metaclass=ABCMeta):
|
|||
Returns:
|
||||
dict: newly constructed transaction.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def sign_transaction(transaction, *args, **kwargs):
|
||||
"""Sign a transaction.
|
||||
|
@ -74,20 +75,19 @@ class AbstractConsensusRules(metaclass=ABCMeta):
|
|||
Returns:
|
||||
dict: transaction with any signatures applied.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def verify_signature(signed_transaction):
|
||||
"""Verify the signature of a transaction.
|
||||
def validate_fulfillments(signed_transaction):
|
||||
"""Validate the fulfillments of a transaction.
|
||||
|
||||
Args:
|
||||
signed_transaction (dict): signed transaction to verify
|
||||
|
||||
Returns:
|
||||
bool: True if the transaction's required signature data is present
|
||||
bool: True if the transaction's required fulfillments are present
|
||||
and correct, False otherwise.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class BaseConsensusRules(AbstractConsensusRules):
|
||||
|
@ -157,8 +157,8 @@ class BaseConsensusRules(AbstractConsensusRules):
|
|||
if calculated_hash != transaction['id']:
|
||||
raise exceptions.InvalidHash()
|
||||
|
||||
# Check signature
|
||||
if not util.verify_signature(transaction):
|
||||
# Check fulfillments
|
||||
if not util.validate_fulfillments(transaction):
|
||||
raise exceptions.InvalidSignature()
|
||||
|
||||
return transaction
|
||||
|
@ -216,10 +216,10 @@ class BaseConsensusRules(AbstractConsensusRules):
|
|||
return util.sign_tx(transaction, private_key)
|
||||
|
||||
@staticmethod
|
||||
def verify_signature(signed_transaction):
|
||||
"""Verify the signature of a transaction.
|
||||
def validate_fulfillments(signed_transaction):
|
||||
"""Validate the fulfillments of a transaction.
|
||||
|
||||
Refer to the documentation of ``bigchaindb.util.verify_signature``
|
||||
Refer to the documentation of ``bigchaindb.util.validate_fulfillments``
|
||||
"""
|
||||
|
||||
return util.verify_signature(signed_transaction)
|
||||
return util.validate_fulfillments(signed_transaction)
|
||||
|
|
|
@ -25,16 +25,18 @@ class Bigchain(object):
|
|||
consensus_plugin=None):
|
||||
"""Initialize the Bigchain instance
|
||||
|
||||
There are three ways in which the Bigchain instance can get its parameters.
|
||||
The order by which the parameters are chosen are:
|
||||
|
||||
1. Setting them by passing them to the `__init__` method itself.
|
||||
2. Setting them as environment variables
|
||||
3. Reading them from the `config.json` file.
|
||||
A Bigchain instance has several configuration parameters (e.g. host).
|
||||
If a parameter value is passed as an argument to the Bigchain
|
||||
__init__ method, then that is the value it will have.
|
||||
Otherwise, the parameter value will be the value from the local
|
||||
configuration file. If it's not set in that file, then the value
|
||||
will come from an environment variable. If that environment variable
|
||||
isn't set, then the parameter will have its default value (defined in
|
||||
bigchaindb.__init__).
|
||||
|
||||
Args:
|
||||
host (str): hostname where the rethinkdb is running.
|
||||
port (int): port in which rethinkb is running (usually 28015).
|
||||
host (str): hostname where RethinkDB is running.
|
||||
port (int): port in which RethinkDB is running (usually 28015).
|
||||
dbname (str): the name of the database to connect to (usually bigchain).
|
||||
public_key (str): the base58 encoded public key for the ED25519 curve.
|
||||
private_key (str): the base58 encoded private key for the ED25519 curve.
|
||||
|
@ -86,17 +88,17 @@ class Bigchain(object):
|
|||
|
||||
return self.consensus.sign_transaction(transaction, *args, **kwargs)
|
||||
|
||||
def verify_signature(self, signed_transaction, *args, **kwargs):
|
||||
"""Verify the signature(s) of a transaction.
|
||||
def validate_fulfillments(self, signed_transaction, *args, **kwargs):
|
||||
"""Validate the fulfillment(s) of a transaction.
|
||||
|
||||
Refer to the documentation of your consensus plugin.
|
||||
|
||||
Returns:
|
||||
bool: True if the transaction's required signature data is present
|
||||
bool: True if the transaction's required fulfillments are present
|
||||
and correct, False otherwise.
|
||||
"""
|
||||
|
||||
return self.consensus.verify_signature(
|
||||
return self.consensus.validate_fulfillments(
|
||||
signed_transaction, *args, **kwargs)
|
||||
|
||||
def write_transaction(self, signed_transaction, durability='soft'):
|
||||
|
|
|
@ -358,7 +358,7 @@ def fulfill_simple_signature_fulfillment(fulfillment, parsed_fulfillment, fulfil
|
|||
|
||||
Args:
|
||||
fulfillment (dict): BigchainDB fulfillment to fulfill.
|
||||
parsed_fulfillment (object): cryptoconditions.Ed25519Fulfillment instance.
|
||||
parsed_fulfillment (cryptoconditions.Ed25519Fulfillment): cryptoconditions.Ed25519Fulfillment instance.
|
||||
fulfillment_message (dict): message to sign.
|
||||
key_pairs (dict): dictionary of (public_key, private_key) pairs.
|
||||
|
||||
|
@ -380,16 +380,16 @@ def fulfill_simple_signature_fulfillment(fulfillment, parsed_fulfillment, fulfil
|
|||
def fulfill_threshold_signature_fulfillment(fulfillment, parsed_fulfillment, fulfillment_message, key_pairs):
|
||||
"""Fulfill a cryptoconditions.ThresholdSha256Fulfillment
|
||||
|
||||
Args:
|
||||
fulfillment (dict): BigchainDB fulfillment to fulfill.
|
||||
parsed_fulfillment (object): cryptoconditions.ThresholdSha256Fulfillment instance.
|
||||
fulfillment_message (dict): message to sign.
|
||||
key_pairs (dict): dictionary of (public_key, private_key) pairs.
|
||||
Args:
|
||||
fulfillment (dict): BigchainDB fulfillment to fulfill.
|
||||
parsed_fulfillment (cryptoconditions.ThresholdSha256Fulfillment): cryptoconditions.ThresholdSha256Fulfillment instance.
|
||||
fulfillment_message (dict): message to sign.
|
||||
key_pairs (dict): dictionary of (public_key, private_key) pairs.
|
||||
|
||||
Returns:
|
||||
object: fulfilled cryptoconditions.ThresholdSha256Fulfillment
|
||||
Returns:
|
||||
object: fulfilled cryptoconditions.ThresholdSha256Fulfillment
|
||||
|
||||
"""
|
||||
"""
|
||||
parsed_fulfillment_copy = copy.deepcopy(parsed_fulfillment)
|
||||
parsed_fulfillment.subconditions = []
|
||||
|
||||
|
@ -421,11 +421,11 @@ def check_hash_and_signature(transaction):
|
|||
raise exceptions.InvalidHash()
|
||||
|
||||
# Check signature
|
||||
if not verify_signature(transaction):
|
||||
if not validate_fulfillments(transaction):
|
||||
raise exceptions.InvalidSignature()
|
||||
|
||||
|
||||
def verify_signature(signed_transaction):
|
||||
def validate_fulfillments(signed_transaction):
|
||||
"""Verify the signature of a transaction
|
||||
|
||||
A valid transaction should have been signed `current_owner` corresponding private key.
|
||||
|
|
|
@ -75,8 +75,8 @@ def create_transaction():
|
|||
tx = util.transform_create(tx)
|
||||
tx = bigchain.consensus.sign_transaction(tx, private_key=bigchain.me_private)
|
||||
|
||||
if not bigchain.consensus.verify_signature(tx):
|
||||
val['error'] = 'Invalid transaction signature'
|
||||
if not bigchain.consensus.validate_fulfillments(tx):
|
||||
val['error'] = 'Invalid transaction fulfillments'
|
||||
|
||||
with monitor.timer('write_transaction', rate=bigchaindb.config['statsd']['rate']):
|
||||
val = bigchain.write_transaction(tx)
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 27 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 12 KiB |
|
@ -30,7 +30,7 @@ validate_transaction(bigchain, transaction)
|
|||
validate_block(bigchain, block)
|
||||
create_transaction(*args, **kwargs)
|
||||
sign_transaction(transaction, *args, **kwargs)
|
||||
verify_signature(transaction)
|
||||
validate_fulfillments(transaction)
|
||||
```
|
||||
|
||||
Together, these functions are sufficient for most customizations. For example:
|
||||
|
|
|
@ -22,9 +22,9 @@ Table of Contents
|
|||
python-driver-api-examples
|
||||
local-rethinkdb-cluster
|
||||
deploy-on-aws
|
||||
json-serialization
|
||||
cryptography
|
||||
models
|
||||
json-serialization
|
||||
developer-interface
|
||||
consensus
|
||||
monitoring
|
||||
|
|
|
@ -12,7 +12,6 @@ First, make sure you have RethinkDB and BigchainDB _installed and running_, i.e.
|
|||
```text
|
||||
$ rethinkdb
|
||||
$ bigchaindb configure
|
||||
$ bigchaindb init
|
||||
$ bigchaindb start
|
||||
```
|
||||
|
||||
|
@ -44,20 +43,20 @@ In BigchainDB, only the federation nodes are allowed to create digital assets, b
|
|||
```python
|
||||
from bigchaindb import crypto
|
||||
|
||||
# create a test user
|
||||
# Create a test user
|
||||
testuser1_priv, testuser1_pub = crypto.generate_key_pair()
|
||||
|
||||
# define a digital asset data payload
|
||||
# Define a digital asset data payload
|
||||
digital_asset_payload = {'msg': 'Hello BigchainDB!'}
|
||||
|
||||
# a create transaction uses the operation `CREATE` and has no inputs
|
||||
# A create transaction uses the operation `CREATE` and has no inputs
|
||||
tx = b.create_transaction(b.me, testuser1_pub, None, 'CREATE', payload=digital_asset_payload)
|
||||
|
||||
# all transactions need to be signed by the user creating the transaction
|
||||
# All transactions need to be signed by the user creating the transaction
|
||||
tx_signed = b.sign_transaction(tx, b.me_private)
|
||||
|
||||
# write the transaction to the bigchain
|
||||
# the transaction will be stored in a backlog where it will be validated,
|
||||
# Write the transaction to the bigchain.
|
||||
# The transaction will be stored in a backlog where it will be validated,
|
||||
# included in a block, and written to the bigchain
|
||||
b.write_transaction(tx_signed)
|
||||
```
|
||||
|
@ -66,7 +65,7 @@ b.write_transaction(tx_signed)
|
|||
|
||||
After a couple of seconds, we can check if the transactions was included in the bigchain:
|
||||
```python
|
||||
# retrieve a transaction from the bigchain
|
||||
# Retrieve a transaction from the bigchain
|
||||
tx_retrieved = b.get_transaction(tx_signed['id'])
|
||||
tx_retrieved
|
||||
```
|
||||
|
@ -119,16 +118,16 @@ tx_retrieved
|
|||
|
||||
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`.
|
||||
Note that the current owner (with public key `3LQ5dTiddXymDhNzETB1rEkp4mA7fEV1Qeiu5ghHiJm9`) is the federation node which created the asset and assigned it to `testuser1`.
|
||||
|
||||
## Transfer the Digital Asset
|
||||
|
||||
Now that `testuser1` has a digital asset assigned to him, he can transfer it to another user. Transfer transactions require an input. The input will be the transaction id of a digital asset that was assigned to `testuser1`, which in our case is `cdb6331f26ecec0ee7e67e4d5dcd63734e7f75bbd1ebe40699fc6d2960ae4cb2`.
|
||||
Now that `testuser1` has a digital asset assigned to him, he can transfer it to another user. Transfer transactions require an input. The input will be the transaction id of a digital asset that was assigned to `testuser1`, which in our case is `933cd83a419d2735822a2154c84176a2f419cbd449a74b94e592ab807af23861`.
|
||||
|
||||
BigchainDB makes use of the crypto-conditions library to both cryptographically lock and unlock transactions.
|
||||
The locking script is refered to as a `condition` and a corresponding `fulfillment` unlocks the condition of the `input_tx`.
|
||||
|
||||
Since a transaction can have multiple outputs with each their own (crypto)condition, each transaction input should also refer to the condition index `cid`.
|
||||
Since a transaction can have multiple outputs with each its own (crypto)condition, each transaction input should also refer to the condition index `cid`.
|
||||
|
||||
![BigchainDB transactions connecting fulfillments with conditions](./_static/tx_single_condition_single_fulfillment_v1.png)
|
||||
|
||||
|
@ -230,14 +229,16 @@ DoubleSpend: input `{'cid': 0, 'txid': '933cd83a419d2735822a2154c84176a2f419cbd4
|
|||
|
||||
## Multiple Owners
|
||||
|
||||
When creating a transaction to a group of people with shared ownership of the asset, one can simply provide a list of `new_owners`:
|
||||
To create a new digital asset with _multiple_ owners, one can simply provide a list 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
|
||||
# Have the federation node sign the transaction
|
||||
tx_multisig_signed = b.sign_transaction(tx_multisig, b.me_private)
|
||||
|
||||
# Write the transaction
|
||||
b.write_transaction(tx_multisig_signed)
|
||||
|
||||
# Check if the transaction is already in the bigchain
|
||||
|
@ -320,7 +321,7 @@ tx_multisig_transfer = b.create_transaction([testuser1_pub, testuser2_pub], test
|
|||
# Sign with both private keys
|
||||
tx_multisig_transfer_signed = b.sign_transaction(tx_multisig_transfer, [testuser1_priv, testuser2_priv])
|
||||
|
||||
# Write to bigchain
|
||||
# Write the transaction
|
||||
b.write_transaction(tx_multisig_transfer_signed)
|
||||
|
||||
# Check if the transaction is already in the bigchain
|
||||
|
@ -330,7 +331,6 @@ tx_multisig_transfer_retrieved
|
|||
|
||||
```python
|
||||
{
|
||||
"assignee":"3LQ5dTiddXymDhNzETB1rEkp4mA7fEV1Qeiu5ghHiJm9",
|
||||
"id":"e689e23f774e7c562eeb310c7c712b34fb6210bea5deb9175e48b68810029150",
|
||||
"transaction":{
|
||||
"conditions":[
|
||||
|
@ -394,7 +394,7 @@ owned_mimo_inputs = b.get_owned_ids(testuser1_pub)
|
|||
# Check the number of assets
|
||||
print(len(owned_mimo_inputs))
|
||||
|
||||
# Create a TRANSFER transaction with all the assets
|
||||
# Create a signed TRANSFER transaction with all the assets
|
||||
tx_mimo = b.create_transaction(testuser1_pub, testuser2_pub, owned_mimo_inputs, 'TRANSFER')
|
||||
tx_mimo_signed = b.sign_transaction(tx_mimo, testuser1_priv)
|
||||
|
||||
|
@ -694,7 +694,7 @@ threshold_tx_transfer['transaction']['fulfillments'][0]['fulfillment'] = thresho
|
|||
|
||||
# Optional validation checks
|
||||
assert threshold_fulfillment.validate(threshold_tx_fulfillment_message) == True
|
||||
assert b.verify_signature(threshold_tx_transfer) == True
|
||||
assert b.validate_fulfillments(threshold_tx_transfer) == True
|
||||
assert b.validate_transaction(threshold_tx_transfer)
|
||||
|
||||
b.write_transaction(threshold_tx_transfer)
|
||||
|
@ -703,7 +703,6 @@ threshold_tx_transfer
|
|||
|
||||
```python
|
||||
{
|
||||
"assignee":"3LQ5dTiddXymDhNzETB1rEkp4mA7fEV1Qeiu5ghHiJm9",
|
||||
"id":"a45b2340c59df7422a5788b3c462dee708a18cdf09d1a10bd26be3f31af4b8d7",
|
||||
"transaction":{
|
||||
"conditions":[
|
||||
|
@ -750,9 +749,13 @@ threshold_tx_transfer
|
|||
|
||||
### 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.
|
||||
A hash-lock condition on an asset is like a password condition: anyone with the secret preimage (like a password) can fulfill the hash-lock condition and transfer the asset to themselves.
|
||||
|
||||
One possible usecase might be to redeem a digital voucher when given a secret (voucher code).
|
||||
Under the hood, fulfilling a hash-lock condition amounts to finding a string (a "preimage") which, when hashed, results in a given value. It's easy to verify that a given preimage hashes to the given value, but it's computationally difficult to _find_ a string which hashes to the given value. The only practical way to get a valid preimage is to get it from the original creator (possibly via intermediaries).
|
||||
|
||||
One possible use case is to distribute preimages as "digital vouchers." The first person to redeem a voucher will get the associated asset.
|
||||
|
||||
A federation node can create an asset with a hash-lock condition and no `new_owners`. Anyone who can fullfill the hash-lock condition can transfer the asset to themselves.
|
||||
|
||||
```python
|
||||
# Create a hash-locked asset without any new_owners
|
||||
|
@ -771,7 +774,7 @@ hashlock_tx['transaction']['conditions'].append({
|
|||
'new_owners': None
|
||||
})
|
||||
|
||||
# Conditions have been updated, so hash needs updating
|
||||
# Conditions have been updated, so the hash needs updating
|
||||
hashlock_tx['id'] = util.get_hash_data(hashlock_tx)
|
||||
|
||||
# The asset needs to be signed by the current_owner
|
||||
|
@ -787,7 +790,6 @@ hashlock_tx_signed
|
|||
|
||||
```python
|
||||
{
|
||||
"assignee":"FmLm6MxCABc8TsiZKdeYaZKo5yZWMM6Vty7Q1B6EgcP2",
|
||||
"id":"604c520244b7ff63604527baf269e0cbfb887122f503703120fd347d6b99a237",
|
||||
"transaction":{
|
||||
"conditions":[
|
||||
|
@ -817,22 +819,22 @@ hashlock_tx_signed
|
|||
}
|
||||
```
|
||||
|
||||
In order to redeem the asset, one needs to create a fulfillment the correct secret as a preimage:
|
||||
In order to redeem the asset, one needs to create a fulfillment with the correct secret:
|
||||
|
||||
```python
|
||||
hashlockuser_priv, hashlockuser_pub = crypto.generate_key_pair()
|
||||
|
||||
# create hashlock fulfillment tx
|
||||
# Create hashlock fulfillment tx
|
||||
hashlock_fulfill_tx = b.create_transaction(None, hashlockuser_pub, {'txid': hashlock_tx['id'], 'cid': 0}, 'TRANSFER')
|
||||
|
||||
# provide a wrong secret
|
||||
# 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
|
||||
# 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()
|
||||
|
@ -846,7 +848,6 @@ hashlock_fulfill_tx
|
|||
|
||||
```python
|
||||
{
|
||||
"assignee":"FmLm6MxCABc8TsiZKdeYaZKo5yZWMM6Vty7Q1B6EgcP2",
|
||||
"id":"fe6871bf3ca62eb61c52c5555cec2e07af51df817723f0cb76e5cf6248f449d2",
|
||||
"transaction":{
|
||||
"conditions":[
|
||||
|
|
6
setup.py
6
setup.py
|
@ -35,6 +35,10 @@ docs_require = [
|
|||
'sphinx-rtd-theme>=0.1.9',
|
||||
]
|
||||
|
||||
benchmarks_require = [
|
||||
'line-profiler==1.0',
|
||||
]
|
||||
|
||||
setup(
|
||||
name='BigchainDB',
|
||||
version=version['__version__'],
|
||||
|
@ -88,7 +92,7 @@ setup(
|
|||
tests_require=tests_require,
|
||||
extras_require={
|
||||
'test': tests_require,
|
||||
'dev': dev_require + tests_require + docs_require,
|
||||
'dev': dev_require + tests_require + docs_require + benchmarks_require,
|
||||
'docs': docs_require,
|
||||
},
|
||||
)
|
||||
|
|
3
speed-tests/README.md
Normal file
3
speed-tests/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Speed Tests
|
||||
|
||||
This folder contains tests related to the code performance of a single node.
|
25
speed-tests/speed_tests.py
Normal file
25
speed-tests/speed_tests.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
from line_profiler import LineProfiler
|
||||
|
||||
import bigchaindb
|
||||
|
||||
|
||||
def speedtest_validate_transaction():
|
||||
# create a transaction
|
||||
b = bigchaindb.Bigchain()
|
||||
tx = b.create_transaction(b.me, b.me, None, 'CREATE')
|
||||
tx_signed = b.sign_transaction(tx, b.me_private)
|
||||
|
||||
# setup the profiler
|
||||
profiler = LineProfiler()
|
||||
profiler.enable_by_count()
|
||||
profiler.add_function(bigchaindb.Bigchain.validate_transaction)
|
||||
|
||||
# validate_transaction 1000 times
|
||||
for i in range(1000):
|
||||
b.validate_transaction(tx_signed)
|
||||
|
||||
profiler.print_stats()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
speedtest_validate_transaction()
|
|
@ -37,7 +37,7 @@ class TestBigchainApi(object):
|
|||
@pytest.mark.usefixtures('inputs')
|
||||
def test_create_transaction_transfer(self, b, user_vk, user_sk):
|
||||
input_tx = b.get_owned_ids(user_vk).pop()
|
||||
assert b.verify_signature(b.get_transaction(input_tx['txid'])) == True
|
||||
assert b.validate_fulfillments(b.get_transaction(input_tx['txid'])) == True
|
||||
|
||||
tx = b.create_transaction(user_vk, b.me, input_tx, 'TRANSFER')
|
||||
|
||||
|
@ -46,8 +46,8 @@ class TestBigchainApi(object):
|
|||
|
||||
tx_signed = b.sign_transaction(tx, user_sk)
|
||||
|
||||
assert b.verify_signature(tx) == False
|
||||
assert b.verify_signature(tx_signed) == True
|
||||
assert b.validate_fulfillments(tx) == False
|
||||
assert b.validate_fulfillments(tx_signed) == True
|
||||
|
||||
def test_transaction_hash(self, b, user_vk):
|
||||
payload = {'cats': 'are awesome'}
|
||||
|
@ -73,7 +73,7 @@ class TestBigchainApi(object):
|
|||
tx_signed = b.sign_transaction(tx, user_sk)
|
||||
|
||||
assert tx_signed['transaction']['fulfillments'][0]['fulfillment'] is not None
|
||||
assert b.verify_signature(tx_signed)
|
||||
assert b.validate_fulfillments(tx_signed)
|
||||
|
||||
def test_serializer(self, b, user_vk):
|
||||
tx = b.create_transaction(user_vk, user_vk, None, 'CREATE')
|
||||
|
@ -714,8 +714,8 @@ class TestBigchainBlock(object):
|
|||
# run bootstrap
|
||||
initial_results = block.bootstrap()
|
||||
|
||||
# we should have gotten a queue with 100 results
|
||||
assert initial_results.qsize() - 1 == 100
|
||||
# we should have gotten a queue with 100 results minus the poison pills
|
||||
assert initial_results.qsize() - mp.cpu_count() == 100
|
||||
|
||||
def test_start(self, b, user_vk):
|
||||
# start with 100 transactions in the backlog and 100 in the changefeed
|
||||
|
@ -736,7 +736,9 @@ class TestBigchainBlock(object):
|
|||
tx = b.sign_transaction(tx, b.me_private)
|
||||
b.write_transaction(tx)
|
||||
new_transactions.put(tx)
|
||||
new_transactions.put('stop')
|
||||
|
||||
for i in range(mp.cpu_count()):
|
||||
new_transactions.put('stop')
|
||||
|
||||
# create a block instance
|
||||
block = Block(new_transactions)
|
||||
|
@ -744,6 +746,8 @@ class TestBigchainBlock(object):
|
|||
# start the block processes
|
||||
block.start()
|
||||
|
||||
time.sleep(6)
|
||||
|
||||
assert new_transactions.qsize() == 0
|
||||
assert r.table('backlog').count() == 0
|
||||
assert r.table('bigchain').count() == 2
|
||||
|
@ -755,20 +759,14 @@ class TestBigchainBlock(object):
|
|||
# create block instance
|
||||
block = Block(new_transactions)
|
||||
|
||||
# create block_process
|
||||
p_block = mp.Process(target=block.start)
|
||||
|
||||
# start block process
|
||||
p_block.start()
|
||||
block.start()
|
||||
|
||||
# wait for 6 seconds to give it time for an empty queue exception to occur
|
||||
time.sleep(6)
|
||||
|
||||
# send the poison pill
|
||||
new_transactions.put('stop')
|
||||
|
||||
# join the process
|
||||
p_block.join()
|
||||
block.kill()
|
||||
|
||||
def test_duplicated_transactions(self):
|
||||
pytest.skip('We may have duplicates in the initial_results and changefeed')
|
||||
|
@ -1218,7 +1216,7 @@ class TestCryptoconditions(object):
|
|||
|
||||
assert fulfillment['current_owners'][0] == b.me
|
||||
assert fulfillment_from_uri.public_key.to_ascii().decode() == b.me
|
||||
assert b.verify_signature(tx_signed) == True
|
||||
assert b.validate_fulfillments(tx_signed) == True
|
||||
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
|
@ -1250,7 +1248,7 @@ class TestCryptoconditions(object):
|
|||
assert fulfillment['current_owners'][0] == user_vk
|
||||
assert fulfillment_from_uri.public_key.to_ascii().decode() == user_vk
|
||||
assert fulfillment_from_uri.condition.serialize_uri() == prev_condition['uri']
|
||||
assert b.verify_signature(tx_signed) == True
|
||||
assert b.validate_fulfillments(tx_signed) == True
|
||||
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||
|
||||
def test_override_condition_create(self, b, user_vk):
|
||||
|
@ -1268,7 +1266,7 @@ class TestCryptoconditions(object):
|
|||
|
||||
assert fulfillment['current_owners'][0] == b.me
|
||||
assert fulfillment_from_uri.public_key.to_ascii().decode() == b.me
|
||||
assert b.verify_signature(tx_signed) == True
|
||||
assert b.validate_fulfillments(tx_signed) == True
|
||||
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
|
@ -1290,7 +1288,7 @@ class TestCryptoconditions(object):
|
|||
|
||||
assert fulfillment['current_owners'][0] == user_vk
|
||||
assert fulfillment_from_uri.public_key.to_ascii().decode() == user_vk
|
||||
assert b.verify_signature(tx_signed) == True
|
||||
assert b.validate_fulfillments(tx_signed) == True
|
||||
assert b.is_valid_transaction(tx_signed) == tx_signed
|
||||
|
||||
def test_override_fulfillment_create(self, b, user_vk):
|
||||
|
@ -1302,7 +1300,7 @@ class TestCryptoconditions(object):
|
|||
|
||||
tx['transaction']['fulfillments'][0]['fulfillment'] = fulfillment.serialize_uri()
|
||||
|
||||
assert b.verify_signature(tx) == True
|
||||
assert b.validate_fulfillments(tx) == True
|
||||
assert b.is_valid_transaction(tx) == tx
|
||||
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
|
@ -1319,7 +1317,7 @@ class TestCryptoconditions(object):
|
|||
|
||||
tx['transaction']['fulfillments'][0]['fulfillment'] = fulfillment.serialize_uri()
|
||||
|
||||
assert b.verify_signature(tx) == True
|
||||
assert b.validate_fulfillments(tx) == True
|
||||
assert b.is_valid_transaction(tx) == tx
|
||||
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
|
@ -1573,7 +1571,7 @@ class TestCryptoconditions(object):
|
|||
assert tx_transfer_signed['transaction']['fulfillments'][0]['fulfillment'] \
|
||||
== expected_fulfillment.serialize_uri()
|
||||
|
||||
assert b.verify_signature(tx_transfer_signed) is True
|
||||
assert b.validate_fulfillments(tx_transfer_signed) is True
|
||||
|
||||
def test_create_asset_with_hashlock_condition(self, b):
|
||||
hashlock_tx = b.create_transaction(b.me, None, None, 'CREATE')
|
||||
|
|
|
@ -233,7 +233,7 @@ assert threshold_fulfillment.validate(threshold_tx_fulfillment_message) == True
|
|||
|
||||
threshold_tx_transfer['transaction']['fulfillments'][0]['fulfillment'] = threshold_fulfillment.serialize_uri()
|
||||
|
||||
assert b.verify_signature(threshold_tx_transfer) == True
|
||||
assert b.validate_fulfillments(threshold_tx_transfer) == True
|
||||
|
||||
assert b.validate_transaction(threshold_tx_transfer) == threshold_tx_transfer
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ def test_client_can_create_assets(mock_requests_post, client):
|
|||
assert tx['transaction']['conditions'][0]['new_owners'][0] == client.public_key
|
||||
assert tx['transaction']['fulfillments'][0]['input'] is None
|
||||
|
||||
assert util.verify_signature(tx)
|
||||
assert util.validate_fulfillments(tx)
|
||||
|
||||
|
||||
def test_client_can_transfer_assets(mock_requests_post, mock_bigchaindb_sign, client):
|
||||
|
|
|
@ -34,7 +34,7 @@ def test_transform_create(b, user_sk, user_vk):
|
|||
|
||||
assert tx['transaction']['fulfillments'][0]['current_owners'][0] == b.me
|
||||
assert tx['transaction']['conditions'][0]['new_owners'][0] == user_vk
|
||||
assert util.verify_signature(tx)
|
||||
assert util.validate_fulfillments(tx)
|
||||
|
||||
|
||||
def test_empty_pool_is_populated_with_instances(mock_queue):
|
||||
|
|
|
@ -58,12 +58,15 @@ def test_load_consensus_plugin_raises_with_invalid_subclass(monkeypatch):
|
|||
# Monkeypatch entry_point.load to return something other than a
|
||||
# ConsensusRules instance
|
||||
from bigchaindb import config_utils
|
||||
import time
|
||||
monkeypatch.setattr(config_utils,
|
||||
'iter_entry_points',
|
||||
lambda *args: [type('entry_point', (object), {'load': lambda: object})])
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
config_utils.load_consensus_plugin()
|
||||
# Since the function is decorated with `lru_cache`, we need to
|
||||
# "miss" the cache using a name that has not been used previously
|
||||
config_utils.load_consensus_plugin(str(time.time()))
|
||||
|
||||
|
||||
def test_map_leafs_iterator():
|
||||
|
|
Loading…
Reference in New Issue
Block a user