diff --git a/bigchaindb/backend/localmongodb/query.py b/bigchaindb/backend/localmongodb/query.py index 4c08827b..dbd072d5 100644 --- a/bigchaindb/backend/localmongodb/query.py +++ b/bigchaindb/backend/localmongodb/query.py @@ -111,3 +111,27 @@ def get_txids_filtered(conn, asset_id, operation=None): @register_query(LocalMongoDBConnection) def text_search(*args, **kwargs): return mongodb.query.text_search(*args, **kwargs) + + +@register_query(LocalMongoDBConnection) +def get_owned_ids(conn, owner): + cursor = conn.run( + conn.collection('transactions').aggregate([ + {'$match': {'outputs.public_keys': owner}}, + {'$project': {'_id': False}} + ])) + return cursor + + +@register_query(LocalMongoDBConnection) +def get_spending_transactions(conn, inputs): + cursor = conn.run( + conn.collection('transactions').aggregate([ + {'$match': { + 'inputs.fulfills': { + '$in': inputs, + }, + }}, + {'$project': {'_id': False}} + ])) + return cursor diff --git a/bigchaindb/tendermint/fastquery.py b/bigchaindb/tendermint/fastquery.py new file mode 100644 index 00000000..7da15b99 --- /dev/null +++ b/bigchaindb/tendermint/fastquery.py @@ -0,0 +1,48 @@ +from bigchaindb.utils import condition_details_has_owner +from bigchaindb.backend import query +from bigchaindb.common.transaction import TransactionLink + + +class FastQuery(): + """ + Database queries that join on block results from a single node. + """ + + def get_outputs_by_public_key(self, public_key): + """ + Get outputs for a public key + """ + txs = list(query.get_owned_ids(self.connection, public_key)) + return [TransactionLink(tx['id'], index) + for tx in txs + for index, output in enumerate(tx['outputs']) + if condition_details_has_owner(output['condition']['details'], + public_key)] + + def filter_spent_outputs(self, outputs): + """ + Remove outputs that have been spent + + Args: + outputs: list of TransactionLink + """ + links = [o.to_dict() for o in outputs] + txs = list(query.get_spending_transactions(self.connection, links)) + spends = {TransactionLink.from_dict(input_['fulfills']) + for tx in txs + for input_ in tx['inputs']} + return [ff for ff in outputs if ff not in spends] + + def filter_unspent_outputs(self, outputs): + """ + Remove outputs that have not been spent + + Args: + outputs: list of TransactionLink + """ + links = [o.to_dict() for o in outputs] + txs = list(query.get_spending_transactions(self.connection, links)) + spends = {TransactionLink.from_dict(input_['fulfills']) + for tx in txs + for input_ in tx['inputs']} + return [ff for ff in outputs if ff in spends] diff --git a/bigchaindb/tendermint/lib.py b/bigchaindb/tendermint/lib.py index 5b0f1bdb..67f899e4 100644 --- a/bigchaindb/tendermint/lib.py +++ b/bigchaindb/tendermint/lib.py @@ -11,6 +11,7 @@ from bigchaindb import Bigchain from bigchaindb.models import Transaction from bigchaindb.common.exceptions import SchemaValidationError, ValidationError from bigchaindb.tendermint.utils import encode_transaction +from bigchaindb.tendermint import fastquery logger = logging.getLogger(__name__) @@ -117,5 +118,9 @@ class BigchainDB(Bigchain): return False return transaction + @property + def fastquery(self): + return fastquery.FastQuery(self.connection, self.me) + Block = namedtuple('Block', ('app_hash', 'height')) diff --git a/docs/root/source/assets.rst b/docs/root/source/assets.rst index f08deaf0..a0aa5a31 100644 --- a/docs/root/source/assets.rst +++ b/docs/root/source/assets.rst @@ -6,19 +6,11 @@ BigchainDB can store data of any kind (within reason), but it's designed to be p * The fundamental thing that one sends to a BigchainDB cluster, to be checked and stored (if valid), is a *transaction*, and there are two kinds: CREATE transactions and TRANSFER transactions. * A CREATE transaction can be use to register any kind of asset (divisible or indivisible), along with arbitrary metadata. * An asset can have zero, one, or several owners. -* The owners of an asset can specify (crypto-)conditions which must be satisfied by anyone wishing transfer the asset to new owners. For example, a condition might be that at least 3 of the 5 current owners must cryptographically sign a transfer transaction. -* BigchainDB verifies that the conditions have been satisfied as part of checking the validity of transfer transactions. (Moreover, anyone can check that they were satisfied.) +* The owners of an asset can specify (crypto-)conditions which must be satisfied by anyone wishing transfer the asset to new owners. For example, a condition might be that at least 3 of the 5 current owners must cryptographically sign a TRANSFER transaction. +* BigchainDB verifies that the conditions have been satisfied as part of checking the validity of TRANSFER transactions. (Moreover, anyone can check that they were satisfied.) * BigchainDB prevents double-spending of an asset. -* Validated transactions are strongly tamper-resistant; see :doc:`the page about immutability `. - - -BigchainDB Integration with Other Blockchains ---------------------------------------------- - -BigchainDB works with the `Interledger protocol `_, enabling the transfer of assets between BigchainDB and other blockchains, ledgers, and payment systems. - -We’re actively exploring ways that BigchainDB can be used with other blockchains and platforms. +* Validated transactions are :doc:`"immutable" `. .. note:: - We used the word "owners" somewhat loosely above. A more accurate word might be fulfillers, signers, controllers, or transfer-enablers. See BigchainDB Server `issue #626 `_. + We used the word "owners" somewhat loosely above. A more accurate word might be fulfillers, signers, controllers, or transfer-enablers. See the `note about "owners" in the IPDB Transaction Spec `_. diff --git a/docs/root/source/bft.md b/docs/root/source/bft.md index fce8ca3d..919a0df9 100644 --- a/docs/root/source/bft.md +++ b/docs/root/source/bft.md @@ -1,8 +1,6 @@ # BigchainDB and Byzantine Fault Tolerance -While BigchainDB is not currently [Byzantine fault tolerant (BFT)](https://en.wikipedia.org/wiki/Byzantine_fault_tolerance), we plan to offer it as an option. -Update Nov 2017: we're actively working on this, the next release or two will likely have support. More details to come in blog form and github issues - -Related issue: [Issue #293](https://github.com/bigchaindb/bigchaindb/issues/293). We anticipate that turning on BFT will cause a dropoff in performance (for a gain in security). - -In the meantime, there are practical things that one can do to increase security (e.g. firewalls, key management, and access controls). +[BigchainDB Server](https://docs.bigchaindb.com/projects/server/en/latest/index.html) +uses [Tendermint](https://tendermint.com/) +for consensus and transaction replication, +and Tendermint is [Byzantine Fault Tolerant (BFT)](https://en.wikipedia.org/wiki/Byzantine_fault_tolerance). diff --git a/docs/root/source/decentralized.md b/docs/root/source/decentralized.md index c0c213cf..755a84a2 100644 --- a/docs/root/source/decentralized.md +++ b/docs/root/source/decentralized.md @@ -14,8 +14,6 @@ A consortium can increase its decentralization (and its resilience) by increasin There’s no node that has a long-term special position in the cluster. All nodes run the same software and perform the same duties. -MongoDB and RethinkDB have an “admin” user which can’t be deleted and which can make big changes to the database, such as dropping a table. Right now, that’s a big security vulnerability, but we have plans to mitigate it by: -1. Locking down the admin user as much as possible. -2. Having all nodes inspect admin-type requests before acting on them. Requests can be checked against an evolving whitelist of allowed actions. Nodes requesting non-allowed requests can be removed from the list of cluster nodes. +If someone has (or gets) admin access to a node, they can mess with that node (e.g. change or delete data stored on that node), but those changes should remain isolated to that node. The BigchainDB cluster can only be compromised if more than one third of the nodes get compromised. See the [Tendermint documentation](https://tendermint.readthedocs.io/projects/tools/en/master/introduction.html) for more details. -It’s worth noting that the admin user can’t transfer assets, even today. The only way to create a valid transfer transaction is to fulfill the current (crypto) conditions on the asset, and the admin user can’t do that because the admin user doesn’t have the necessary private keys (or preimages, in the case of hashlock conditions). They’re not stored in the database. +It’s worth noting that not even the admin or superuser of a node can transfer assets. The only way to create a valid transfer transaction is to fulfill the current crypto-conditions on the asset, and the admin/superuser can’t do that because the admin user doesn’t have the necessary information (e.g. private keys). diff --git a/docs/root/source/diversity.md b/docs/root/source/diversity.md index 20c9afb5..767962e1 100644 --- a/docs/root/source/diversity.md +++ b/docs/root/source/diversity.md @@ -1,11 +1,10 @@ # Kinds of Node Diversity -Steps should be taken to make it difficult for any one actor or event to control or damage “enough” of the nodes. (“Enough” is usually a quorum.) There are many kinds of diversity to consider, listed below. It may be quite difficult to have high diversity of all kinds. +Steps should be taken to make it difficult for any one actor or event to control or damage “enough” of the nodes. (Because BigchainDB Server uses Tendermint, "enough" is ⅓.) There are many kinds of diversity to consider, listed below. It may be quite difficult to have high diversity of all kinds. 1. **Jurisdictional diversity.** The nodes should be controlled by entities within multiple legal jurisdictions, so that it becomes difficult to use legal means to compel enough of them to do something. -2. **Geographic diversity.** The servers should be physically located at multiple geographic locations, so that it becomes difficult for a natural disaster (such as a flood or earthquake) to damage enough of them to cause problems. -3. **Hosting diversity.** The servers should be hosted by multiple hosting providers (e.g. Amazon Web Services, Microsoft Azure, Digital Ocean, Rackspace), so that it becomes difficult for one hosting provider to influence enough of the nodes. -4. **Operating system diversity.** The servers should use a variety of operating systems, so that a security bug in one OS can’t be used to exploit enough of the nodes. -5. **Diversity in general.** In general, membership diversity (of all kinds) confers many advantages on a consortium. For example, it provides the consortium with a source of various ideas for addressing challenges. +1. **Geographic diversity.** The servers should be physically located at multiple geographic locations, so that it becomes difficult for a natural disaster (such as a flood or earthquake) to damage enough of them to cause problems. +1. **Hosting diversity.** The servers should be hosted by multiple hosting providers (e.g. Amazon Web Services, Microsoft Azure, Digital Ocean, Rackspace), so that it becomes difficult for one hosting provider to influence enough of the nodes. +1. **Diversity in general.** In general, membership diversity (of all kinds) confers many advantages on a consortium. For example, it provides the consortium with a source of various ideas for addressing challenges. -Note: If all the nodes are running the same code, i.e. the same implementation of BigchainDB, then a bug in that code could be used to compromise all of the nodes. Ideally, there would be several different, well-maintained implementations of BigchainDB Server (e.g. one in Python, one in Go, etc.), so that a consortium could also have a diversity of server implementations. +Note: If all the nodes are running the same code, i.e. the same implementation of BigchainDB, then a bug in that code could be used to compromise all of the nodes. Ideally, there would be several different, well-maintained implementations of BigchainDB Server (e.g. one in Python, one in Go, etc.), so that a consortium could also have a diversity of server implementations. Similar remarks can be made about the operating system. diff --git a/docs/root/source/index.rst b/docs/root/source/index.rst index 71fdd022..be2f5f1b 100644 --- a/docs/root/source/index.rst +++ b/docs/root/source/index.rst @@ -2,13 +2,12 @@ BigchainDB Documentation ======================== `BigchainDB `_ is a scalable blockchain database. -That is, it's a "big data" database with some blockchain characteristics added, including `decentralization `_, +It has some database characteristics and some blockchain characteristics, +including `decentralization `_, `immutability `_ -and -`native support for assets `_. -You can read about the motivations, goals and high-level architecture in the `BigchainDB whitepaper `_. +and `native support for assets `_. -At a high level, one can communicate with a BigchainDB cluster (set of nodes) using the BigchainDB Client-Server HTTP API, or a wrapper for that API, such as the BigchainDB Python Driver. Each BigchainDB node runs BigchainDB Server and various other software. The `terminology page `_ explains some of those terms in more detail. +At a high level, one can communicate with a BigchainDB cluster (set of nodes) using the BigchainDB HTTP API, or a wrapper for that API, such as the BigchainDB Python Driver. Each BigchainDB node runs BigchainDB Server and various other software. The `terminology page `_ explains some of those terms in more detail. .. raw:: html @@ -79,7 +78,6 @@ More About BigchainDB :maxdepth: 1 BigchainDB Docs Home - production-ready terminology decentralized diversity @@ -89,5 +87,4 @@ More About BigchainDB smart-contracts transaction-concepts permissions - timestamps Data Models diff --git a/docs/root/source/permissions.rst b/docs/root/source/permissions.rst index d5972ac0..b934effd 100644 --- a/docs/root/source/permissions.rst +++ b/docs/root/source/permissions.rst @@ -15,7 +15,8 @@ To spend/transfer an unspent output, a user (or group of users) must fulfill the - "…three of these four people must sign." - "…either Bob must sign, or both Tom and Sylvia must sign." -For details, see `the documentation about conditions in BigchainDB `_. +For details, see +`the documentation about conditions in the IPDB Transaction Spec `_. Once an output has been spent, it can't be spent again: *nobody* has permission to do that. That is, BigchainDB doesn't permit anyone to "double spend" an output. diff --git a/docs/root/source/production-ready.md b/docs/root/source/production-ready.md deleted file mode 100644 index 21358c37..00000000 --- a/docs/root/source/production-ready.md +++ /dev/null @@ -1,14 +0,0 @@ -# Production-Ready? - -BigchainDB is not production-ready. You can use it to build a prototype or proof-of-concept (POC); many people are already doing that. -Once BigchainDB is production-ready, we'll make an announcement. - -BigchainDB version numbers follow the conventions of *Semantic Versioning* as documented at [semver.org](http://semver.org/). (For Python stuff, we use [Python's version of Semantic Versioning](https://packaging.python.org/tutorials/distributing-packages/#choosing-a-versioning-scheme).) This means, among other things: - -* Before version 1.0, breaking API changes could happen in any new version, even in a change from version 0.Y.4 to 0.Y.5. - -* Starting with version 1.0.0, breaking API changes will only happen when the MAJOR version changes (e.g. from 1.7.4 to 2.0.0, or from 4.9.3 to 5.0.0). - -To review the release history of some particular BigchainDB software, go to the GitHub repository of that software and click on "Releases". For example, the release history of BigchainDB Server can be found at [https://github.com/bigchaindb/bigchaindb/releases](https://github.com/bigchaindb/bigchaindb/releases). - -[The BigchainDB Roadmap](https://github.com/bigchaindb/org/blob/master/ROADMAP.md) will give you a sense of the things we intend to do with BigchainDB in the near term and the long term. \ No newline at end of file diff --git a/docs/root/source/smart-contracts.rst b/docs/root/source/smart-contracts.rst index 04c0c9bb..143d6dfe 100644 --- a/docs/root/source/smart-contracts.rst +++ b/docs/root/source/smart-contracts.rst @@ -15,5 +15,4 @@ Crypto-conditions can be quite complex. They can't include loops or recursion an .. note:: - We used the word "owners" somewhat loosely above. A more accurate word might be fulfillers, signers, controllers, or transfer-enablers. See BigchainDB Server `issue #626 `_. - \ No newline at end of file + We used the word "owners" somewhat loosely above. A more accurate word might be fulfillers, signers, controllers, or transfer-enablers. See the `note about "owners" in the IPDB Transaction Spec `_. diff --git a/docs/root/source/terminology.md b/docs/root/source/terminology.md index a9ece75d..ef05436e 100644 --- a/docs/root/source/terminology.md +++ b/docs/root/source/terminology.md @@ -2,16 +2,13 @@ There is some specialized terminology associated with BigchainDB. To get started, you should at least know the following: - ## BigchainDB Node -A **BigchainDB node** is a machine or set of closely-linked machines running MongoDB Server (or RethinkDB Server), BigchainDB Server, and related software. Each node is controlled by one person or organization. - +A **BigchainDB node** is a machine (or logical machine) running [BigchainDB Server](https://docs.bigchaindb.com/projects/server/en/latest/introduction.html) and related software. Each node is controlled by one person or organization. ## BigchainDB Cluster -A set of BigchainDB nodes can connect to each other to form a **BigchainDB cluster**. Each node in the cluster runs the same software. A cluster contains one logical MongoDB/RethinkDB datastore. A cluster may have additional machines to do things such as cluster monitoring. - +A set of BigchainDB nodes can connect to each other to form a **BigchainDB cluster**. Each node in the cluster runs the same software. A cluster may have additional machines to do things such as cluster monitoring. ## BigchainDB Consortium diff --git a/docs/root/source/timestamps.md b/docs/root/source/timestamps.md deleted file mode 100644 index 79d5e700..00000000 --- a/docs/root/source/timestamps.md +++ /dev/null @@ -1,84 +0,0 @@ -# Timestamps in BigchainDB - -Each block and vote has an associated timestamp. Interpreting those timestamps is tricky, hence the need for this section. - - -## Timestamp Sources & Accuracy - -Timestamps in BigchainDB are provided by the node which created the block and the node that created the vote. - -When a BigchainDB node needs a timestamp, it calls a BigchainDB utility function named `timestamp()`. There's a detailed explanation of how that function works below, but the short version is that it gets the [Unix time](https://en.wikipedia.org/wiki/Unix_time) from its system clock, rounded to the nearest second. - -We advise BigchainDB nodes to run special software (an "NTP daemon") to keep their system clock in sync with standard time servers. (NTP stands for [Network Time Protocol](https://en.wikipedia.org/wiki/Network_Time_Protocol).) - - -## Converting Timestamps to UTC - -To convert a BigchainDB timestamp (a Unix time) to UTC, you need to know how the node providing the timestamp was set up. That's because different setups will report a different "Unix time" value around leap seconds! There's [a nice Red Hat Developer Blog post about the various setup options](https://developers.redhat.com/blog/2015/06/01/five-different-ways-handle-leap-seconds-ntp/). If you want more details, see [David Mills' pages about leap seconds, NTP, etc.](https://www.eecis.udel.edu/~mills/leap.html) (David Mills designed NTP.) - -We advise BigchainDB nodes to run an NTP daemon with particular settings so that their timestamps are consistent. - -If a timestamp comes from a node that's set up as we advise, it can be converted to UTC as follows: - -1. Use a standard "Unix time to UTC" converter to get a UTC timestamp. -2. Is the UTC timestamp a leap second, or the second before/after a leap second? There's [a list of all the leap seconds on Wikipedia](https://en.wikipedia.org/wiki/Leap_second). -3. If no, then you are done. -4. If yes, then it might not be possible to convert it to a single UTC timestamp. Even if it can't be converted to a single UTC timestamp, it _can_ be converted to a list of two possible UTC timestamps. -Showing how to do that is beyond the scope of this documentation. -In all likelihood, you will never have to worry about leap seconds because they are very rare. -(There were only 26 between 1972 and the end of 2015.) - - -## Calculating Elapsed Time Between Two Timestamps - -There's another gotcha with (Unix time) timestamps: you can't calculate the real-world elapsed time between two timestamps (correctly) by subtracting the smaller timestamp from the larger one. The result won't include any of the leap seconds that occured between the two timestamps. You could look up how many leap seconds happened between the two timestamps and add that to the result. There are many library functions for working with timestamps; those are beyond the scope of this documentation. - - -## Interpreting Sets of Timestamps - -You can look at many timestamps to get a statistical sense of when something happened. For example, a transaction in a decided-valid block has many associated timestamps: - -* the timestamp of the block -* the timestamps of all the votes on the block - - -## How BigchainDB Uses Timestamps - -BigchainDB _doesn't_ use timestamps to determine the order of transactions or blocks. In particular, the order of blocks is determined by MongoDB's oplog (or RethinkDB's changefeed) on the bigchain table. - -BigchainDB does use timestamps for some things. When a Transaction is written to the backlog, a timestamp is assigned called the `assignment_timestamp`, to determine if it has been waiting in the backlog for too long (i.e. because the node assigned to it hasn't handled it yet). - - -## Including Trusted Timestamps - -If you want to create a transaction payload with a trusted timestamp, you can. - -One way to do that would be to send a payload to a trusted timestamping service. They will send back a timestamp, a signature, and their public key. They should also explain how you can verify the signature. You can then include the original payload, the timestamp, the signature, and the service's public key in your transaction metadata. That way, anyone with the verification instructions can verify that the original payload was signed by the trusted timestamping service. - - -## How the timestamp() Function Works - -BigchainDB has a utility function named `timestamp()` which amounts to: -```python -timestamp() = str(round(time.time())) -``` - -In other words, it calls the `time()` function in Python's `time` module, [rounds](https://docs.python.org/3/library/functions.html#round) that to the nearest integer, and converts the result to a string. - -It rounds the output of `time.time()` to the nearest second because, according to [the Python documentation for `time.time()`](https://docs.python.org/3.4/library/time.html#time.time), "...not all systems provide time with a better precision than 1 second." - -How does `time.time()` work? If you look in the C source code, it calls `floattime()` and `floattime()` calls [clock_gettime()](https://www.cs.rutgers.edu/~pxk/416/notes/c-tutorials/gettime.html), if it's available. -```text -ret = clock_gettime(CLOCK_REALTIME, &tp); -``` - -With `CLOCK_REALTIME` as the first argument, it returns the "Unix time." ("Unix time" is in quotes because its value around leap seconds depends on how the system is set up; see above.) - - -## Why Not Use UTC, TAI or Some Other Time that Has Unambiguous Timestamps for Leap Seconds? - -It would be nice to use UTC or TAI timestamps, but unfortunately there's no commonly-available, standard way to get always-accurate UTC or TAI timestamps from the operating system on typical computers today (i.e. accurate around leap seconds). - -There _are_ commonly-available, standard ways to get the "Unix time," such as clock_gettime() function available in C. That's what we use (indirectly via Python). ("Unix time" is in quotes because its value around leap seconds depends on how the system is set up; see above.) - -The Unix-time-based timestamps we use are only ambiguous circa leap seconds, and those are very rare. Even for those timestamps, the extra uncertainty is only one second, and that's not bad considering that we only report timestamps to a precision of one second in the first place. All other timestamps can be converted to UTC with no ambiguity. diff --git a/docs/root/source/transaction-concepts.md b/docs/root/source/transaction-concepts.md index 66c4ec0f..02820ac5 100644 --- a/docs/root/source/transaction-concepts.md +++ b/docs/root/source/transaction-concepts.md @@ -6,7 +6,6 @@ things (e.g. assets). Transactions are the most basic kind of record stored by BigchainDB. There are two kinds: CREATE transactions and TRANSFER transactions. - ## CREATE Transactions A CREATE transaction can be used to register, issue, create or otherwise @@ -31,20 +30,19 @@ Each output also has an associated condition: the condition that must be met BigchainDB supports a variety of conditions, a subset of the [Interledger Protocol (ILP)](https://interledger.org/) crypto-conditions. For details, see -[the documentation about Inputs and Outputs](https://docs.bigchaindb.com/projects/server/en/latest/data-models/inputs-outputs.html). +[the documentation about conditions in the IPDB Transaction Spec](https://the-ipdb-transaction-spec.readthedocs.io/en/latest/transaction-components/conditions.html). Each output also has a list of all the public keys associated with the conditions on that output. Loosely speaking, that list might be interpreted as the list of "owners." A more accurate word might be fulfillers, signers, controllers, or transfer-enablers. -See BigchainDB Server [issue #626](https://github.com/bigchaindb/bigchaindb/issues/626). +See the [note about "owners" in the IPDB Transaction Spec](https://the-ipdb-transaction-spec.readthedocs.io/en/latest/ownership.html). A CREATE transaction must be signed by all the owners. (If you're looking for that signature, it's in the one "fulfillment" of the one input, albeit encoded.) - ## TRANSFER Transactions A TRANSFER transaction can transfer/spend one or more outputs @@ -82,7 +80,6 @@ transferred if both Jack and Kelly sign. Note how the sum of the incoming paperclips must equal the sum of the outgoing paperclips (100). - ## Transaction Validity When a node is asked to check if a transaction is valid, it checks several @@ -90,6 +87,7 @@ things. We documented those things in a post on *The BigchainDB Blog*: ["What is a Valid Transaction in BigchainDB?"](https://blog.bigchaindb.com/what-is-a-valid-transaction-in-bigchaindb-9a1a075a9598) (Note: That post was about BigchainDB Server v1.0.0.) +The [IPDB Transaction Spec documents the conditions for a transaction to be valid](https://the-ipdb-transaction-spec.readthedocs.io/en/latest/transaction-validation.html). ## Example Transactions diff --git a/tests/backend/localmongodb/test_queries.py b/tests/backend/localmongodb/test_queries.py index fc9672d8..5456a68f 100644 --- a/tests/backend/localmongodb/test_queries.py +++ b/tests/backend/localmongodb/test_queries.py @@ -3,10 +3,9 @@ from copy import deepcopy import pytest import pymongo -pytestmark = [pytest.mark.tendermint, pytest.mark.localmongodb] +pytestmark = [pytest.mark.tendermint, pytest.mark.localmongodb, pytest.mark.bdb] -@pytest.mark.bdb def test_get_txids_filtered(signed_create_tx, signed_transfer_tx): from bigchaindb.backend import connect, query from bigchaindb.models import Transaction @@ -32,7 +31,6 @@ def test_get_txids_filtered(signed_create_tx, signed_transfer_tx): assert txids == {signed_transfer_tx.id} -@pytest.mark.bdb def test_write_assets(): from bigchaindb.backend import connect, query conn = connect() @@ -57,7 +55,6 @@ def test_write_assets(): assert list(cursor) == assets[:-1] -@pytest.mark.bdb def test_get_assets(): from bigchaindb.backend import connect, query conn = connect() @@ -74,8 +71,40 @@ def test_get_assets(): assert query.get_asset(conn, asset['id']) -@pytest.mark.bdb def test_text_search(): from ..mongodb.test_queries import test_text_search test_text_search('assets') + + +def test_get_owned_ids(signed_create_tx, user_pk): + from bigchaindb.backend import connect, query + conn = connect() + + # insert a transaction + conn.db.transactions.insert_one(signed_create_tx.to_dict()) + + txns = list(query.get_owned_ids(conn, user_pk)) + + assert txns[0] == signed_create_tx.to_dict() + + +def test_get_spending_transactions(user_pk): + from bigchaindb.backend import connect, query + from bigchaindb.models import Transaction + conn = connect() + + out = [([user_pk], 1)] + tx1 = Transaction.create([user_pk], out * 3) + inputs = tx1.to_inputs() + tx2 = Transaction.transfer([inputs[0]], out, tx1.id) + tx3 = Transaction.transfer([inputs[1]], out, tx1.id) + tx4 = Transaction.transfer([inputs[2]], out, tx1.id) + txns = [tx.to_dict() for tx in [tx1, tx2, tx3, tx4]] + conn.db.transactions.insert_many(txns) + + links = [inputs[0].fulfills.to_dict(), inputs[2].fulfills.to_dict()] + txns = list(query.get_spending_transactions(conn, links)) + + # tx3 not a member because input 1 not asked for + assert txns == [tx2.to_dict(), tx4.to_dict()] diff --git a/tests/tendermint/test_core.py b/tests/tendermint/test_core.py index 80b5cbb4..40b0310e 100644 --- a/tests/tendermint/test_core.py +++ b/tests/tendermint/test_core.py @@ -92,7 +92,7 @@ def test_deliver_transfer_tx__double_spend_fails(b): carly = generate_key_pair() asset = { - "msg": "live long and prosper" + 'msg': 'live long and prosper' } tx = Transaction.create([alice.public_key], diff --git a/tests/web/conftest.py b/tests/web/conftest.py index 213e4b7e..efb0f81b 100644 --- a/tests/web/conftest.py +++ b/tests/web/conftest.py @@ -3,11 +3,10 @@ import pytest @pytest.fixture def app(request): - from bigchaindb import config from bigchaindb.web import server from bigchaindb.tendermint.lib import BigchainDB - if config['database']['backend'] == 'localmongodb': + if request.config.getoption('--database-backend') == 'localmongodb': app = server.create_app(debug=True, bigchaindb_factory=BigchainDB) else: app = server.create_app(debug=True) diff --git a/tests/web/test_outputs.py b/tests/web/test_outputs.py index 8ef90b73..2d5e663d 100644 --- a/tests/web/test_outputs.py +++ b/tests/web/test_outputs.py @@ -6,11 +6,12 @@ pytestmark = [pytest.mark.bdb, pytest.mark.usefixtures('inputs')] OUTPUTS_ENDPOINT = '/api/v1/outputs/' +@pytest.mark.tendermint def test_get_outputs_endpoint(client, user_pk): m = MagicMock() m.txid = 'a' m.output = 0 - with patch('bigchaindb.core.Bigchain.get_outputs_filtered') as gof: + with patch('bigchaindb.tendermint.lib.BigchainDB.get_outputs_filtered') as gof: gof.return_value = [m, m] res = client.get(OUTPUTS_ENDPOINT + '?public_key={}'.format(user_pk)) assert res.json == [ @@ -21,11 +22,12 @@ def test_get_outputs_endpoint(client, user_pk): gof.assert_called_once_with(user_pk, None) +@pytest.mark.tendermint def test_get_outputs_endpoint_unspent(client, user_pk): m = MagicMock() m.txid = 'a' m.output = 0 - with patch('bigchaindb.core.Bigchain.get_outputs_filtered') as gof: + with patch('bigchaindb.tendermint.lib.BigchainDB.get_outputs_filtered') as gof: gof.return_value = [m] params = '?spent=False&public_key={}'.format(user_pk) res = client.get(OUTPUTS_ENDPOINT + params) @@ -34,11 +36,12 @@ def test_get_outputs_endpoint_unspent(client, user_pk): gof.assert_called_once_with(user_pk, False) +@pytest.mark.tendermint def test_get_outputs_endpoint_spent(client, user_pk): m = MagicMock() m.txid = 'a' m.output = 0 - with patch('bigchaindb.core.Bigchain.get_outputs_filtered') as gof: + with patch('bigchaindb.tendermint.lib.BigchainDB.get_outputs_filtered') as gof: gof.return_value = [m] params = '?spent=true&public_key={}'.format(user_pk) res = client.get(OUTPUTS_ENDPOINT + params) @@ -47,11 +50,13 @@ def test_get_outputs_endpoint_spent(client, user_pk): gof.assert_called_once_with(user_pk, True) +@pytest.mark.tendermint def test_get_outputs_endpoint_without_public_key(client): res = client.get(OUTPUTS_ENDPOINT) assert res.status_code == 400 +@pytest.mark.tendermint def test_get_outputs_endpoint_with_invalid_public_key(client): expected = {'message': {'public_key': 'Invalid base58 ed25519 key'}} res = client.get(OUTPUTS_ENDPOINT + '?public_key=abc') @@ -59,6 +64,7 @@ def test_get_outputs_endpoint_with_invalid_public_key(client): assert res.status_code == 400 +@pytest.mark.tendermint def test_get_outputs_endpoint_with_invalid_spent(client, user_pk): expected = {'message': {'spent': 'Boolean value must be "true" or "false" (lowercase)'}} params = '?spent=tru&public_key={}'.format(user_pk)