From a7450341e9d564ce43e31cb795a2a5fd5bd893b3 Mon Sep 17 00:00:00 2001 From: troymc Date: Sun, 23 Oct 2016 17:18:18 +0200 Subject: [PATCH 01/13] Moved contents of models.md to new pages in root docs --- docs/source/topic-guides/models.md | 312 +---------------------------- 1 file changed, 1 insertion(+), 311 deletions(-) diff --git a/docs/source/topic-guides/models.md b/docs/source/topic-guides/models.md index 8b66682f..a443e51a 100644 --- a/docs/source/topic-guides/models.md +++ b/docs/source/topic-guides/models.md @@ -1,313 +1,3 @@ # The Transaction, Block and Vote Models -BigchainDB stores all its records in JSON documents. - -The three main kinds of records are transactions, blocks and votes. -_Transactions_ are used to register, issue, create or transfer things (e.g. assets). Multiple transactions are combined with some other metadata to form _blocks_. Nodes vote on blocks. This section is a reference on the details of transactions, blocks and votes. - -Below we often refer to cryptographic hashes, keys and signatures. The details of those are covered in [the section on cryptography](../appendices/cryptography.html). - - -## Some Words of Caution - -BigchainDB is still in the early stages of development. The data models described below may change substantially before BigchainDB reaches a production-ready state (i.e. version 1.0 and higher). - - -## Transaction Concepts - -Transactions are the most basic kind of record stored by BigchainDB. There are two kinds: creation transactions and transfer transactions. - -A _creation transaction_ can be used to register, issue, create or otherwise initiate the history of a single thing (or asset) in BigchainDB. For example, one might register an identity or a creative work. The things are often called "assets" but they might not be literal assets. A creation transaction also establishes the initial owner or owners of the asset. Only a federation node can create a valid creation transaction (but it's usually made based on a message from a client). - -Currently, BigchainDB only supports indivisible assets. You can't split an asset apart into multiple assets, nor can you combine several assets together into one. [Issue #129](https://github.com/bigchaindb/bigchaindb/issues/129) is an enhancement proposal to support divisible assets. - -A _transfer transaction_ can transfer one or more assets to new owners. - -BigchainDB works with the [Interledger Protocol (ILP)](https://interledger.org/), a protocol for transferring assets between different ledgers, blockchains or payment systems. - -The owner(s) of an asset can specifiy conditions (ILP crypto-conditions) which others must fulfill (satisfy) in order to become the new owner(s) of the asset. For example, a crypto-condition might require a signature from the owner, or from m-of-n owners (a threshold condition, e.g. 3-of-4). - -When someone creates a transfer transaction with the goal of changing an asset's owners, they must fulfill the asset's current crypto-conditions (i.e. in a fulfillment), and they must provide new conditions (including the list of new owners). - -Every create transaction contains exactly one fulfillment-condition pair. A transfer transaction can contain multiple fulfillment-condition pairs: one per asset transferred. Every fulfillment in a transfer transaction (input) must correspond to a condition (output) in a previous transaction. The diagram below illustrates some of these concepts: transactions are represented by light grey boxes, fulfillments have a label like `f:0`, and conditions have a label like `c:0`. - -![Tracking the stories of three assets](../_static/stories_3_assets.png) - -To determine the current owner(s) of an asset, find the most recent valid transaction involving it, and then look at the list of owners in the _conditions_ (not the fulfillments). - - -### Transaction Validation - -When a node is asked to check the validity of a transaction, it must do several things; the main things are: - -* schema validation, -* double-spending checks (for transfer transactions), -* hash validation (i.e. is the calculated transaction hash equal to its id?), and -* validation of all fulfillments, including validation of cryptographic signatures if they’re among the conditions. - -The full details of transaction validation can be found in the code for `validate_transaction()` in the `BaseConsensusRules` class of [`consensus.py`](https://github.com/bigchaindb/bigchaindb/blob/master/bigchaindb/consensus.py) (unless other validation rules are being used by a federation, in which case those should be consulted instead). - - -### Mutable and Immutable Assets - -Assets can be mutable (changeable) or immutable. To change a mutable asset, you must create a valid transfer transaction with a payload specifying how it changed (or will change). The data structure (schema) of the change depends on the asset class. If you're inventing a new asset class, you can make up how to describe changes. For a mutable asset in an existing asset class, you should find out how changes are specified for that asset class. That's not something determined by BigchainDB. - - -## The Transaction Model - -```json -{ - "id": "", - "transaction": { - "version": "", - "fulfillments": [""], - "conditions": [""], - "operation": "", - "timestamp": "", - "asset": "", - "metadata": { - "id": "", - "data": "" - } - } -} -``` - -Here's some explanation of the contents of a transaction: - -- `id`: The hash of everything inside the serialized `transaction` body (i.e. `fulfillments`, `conditions`, `operation`, `timestamp` and `data`; see below), with one wrinkle: for each fulfillment in `fulfillments`, `fulfillment` is set to `null`. The `id` is also the database primary key. -- `transaction`: - - `version`: Version number of the transaction model, so that software can support different transaction models. - - `fulfillments`: List of fulfillments. Each _fulfillment_ contains a pointer to an unspent asset - and a _crypto fulfillment_ that satisfies a spending condition set on the unspent asset. A _fulfillment_ - is usually a signature proving the ownership of the asset. - See [Conditions and Fulfillments](#conditions-and-fulfillments) below. - - `conditions`: List of conditions. Each _condition_ is a _crypto-condition_ that needs to be fulfilled by a transfer transaction in order to transfer ownership to new owners. - See [Conditions and Fulfillments](#conditions-and-fulfillments) below. - - `operation`: String representation of the operation being performed (currently either "CREATE" or "TRANSFER"). It determines how the transaction should be validated. - - `timestamp`: The Unix time when the transaction was created. It's provided by the client. See [the section on timestamps](timestamps.html). - - `asset`: Definition of the digital asset. See next section. - - `metadata`: - - `id`: UUID version 4 (random) converted to a string of hex digits in standard form. - - `data`: Can be any JSON document. It may be empty in the case of a transfer transaction. - -Later, when we get to the models for the block and the vote, we'll see that both include a signature (from the node which created it). You may wonder why transactions don't have signatures... The answer is that they do! They're just hidden inside the `fulfillment` string of each fulfillment. A creation transaction is signed by the node that created it. A transfer transaction is signed by whoever currently controls or owns it. - -What gets signed? For each fulfillment in the transaction, the "fullfillment message" that gets signed includes the `operation`, `timestamp`, `data`, `version`, `id`, corresponding `condition`, and the fulfillment itself, except with its fulfillment string set to `null`. The computed signature goes into creating the `fulfillment` string of the fulfillment. - -One other note: Currently, transactions contain only the public keys of asset-owners (i.e. who own an asset or who owned an asset in the past), inside the conditions and fulfillments. A transaction does _not_ contain the public key of the client (computer) which generated and sent it to a BigchainDB node. In fact, there's no need for a client to _have_ a public/private keypair. In the future, each client may also have a keypair, and it may have to sign each sent transaction (using its private key); see [Issue #347 on GitHub](https://github.com/bigchaindb/bigchaindb/issues/347). In practice, a person might think of their keypair as being both their "ownership-keypair" and their "client-keypair," but there is a difference, just like there's a difference between Joe and Joe's computer. - - -## The Digital Asset Model -To avoid redundant data in transactions the digital asset model is different for `CREATE` and `TRANSFER` transactions. - -The digital asset properties are defined at creation time in a `CREATE` transaction with the following model: -```json -{ - "id": "", - "divisible": "", - "updatable": "", - "refillable": "", - "data": "" -} -``` - -For `TRANSFER` transactions we only keep the asset id. -```json -{ - "id": "", -} -``` - - -- `id`: UUID version 4 (random) converted to a string of hex digits in standard form. Added server side. -- `divisible`: Whether the asset is divisible or not. Defaults to false. -- `updatable`: Whether the data in the asset can be updated in the future or not. Defaults to false. -- `refillable`: Whether the amount of the asset can change after its creation. Defaults to false. -- `data`: A user supplied JSON document with custom information about the asset. Defaults to null. -- _amount_: The amount of "shares". Only relevant if the asset is marked as divisible. Defaults to 1. The amount is not specified in the asset, but in the conditions (see next section). - -At the time of this writing divisible, updatable, and refillable assets are not yet implemented. -See [Issue #487 on Github](https://github.com/bigchaindb/bigchaindb/issues/487) - - -## Conditions and Fulfillments - -To create a transaction that transfers an asset to new owners, one must fulfill the asset’s current conditions (crypto-conditions). The most basic kinds of conditions are: - -* **A hashlock condition:** One can fulfill a hashlock condition by providing the correct “preimage” (similar to a password or secret phrase) -* **A simple signature condition:** One can fulfill a simple signature condition by a providing a valid cryptographic signature (i.e. corresponding to the public key of an owner, usually) -* **A timeout condition:** Anyone can fulfill a timeout condition before the condition’s expiry time. After the expiry time, nobody can fulfill the condition. Another way to say this is that a timeout condition’s fulfillment is valid (TRUE) before the expiry time and invalid (FALSE) after the expiry time. Note: at the time of writing, timeout conditions are BigchainDB-specific (i.e. not part of the Interledger specs). - -A more complex condition can be composed by using n of the above conditions as inputs to an m-of-n threshold condition (a logic gate which outputs TRUE iff m or more inputs are TRUE). If there are n inputs to a threshold condition: -* 1-of-n is the same as a logical OR of all the inputs -* n-of-n is the same as a logical AND of all the inputs - -For example, one could create a condition requiring that m (of n) owners provide signatures before their asset can be transferred to new owners. - -One can also put different weights on the inputs to threshold condition, along with a threshold that the weighted-sum-of-inputs must pass for the output to be TRUE. Weights could be used, for example, to express the number of shares that someone owns in an asset. - -The (single) output of a threshold condition can be used as one of the inputs of other threshold conditions. This means that one can combine threshold conditions to build complex logical expressions, e.g. (x OR y) AND (u OR v). - -Aside: In BigchainDB, the output of an m-of-n threshold condition can be inverted on the way out, so an output that would have been TRUE would get changed to FALSE (and vice versa). This enables the creation of NOT, NOR and NAND gates. At the time of writing, this “inverted threshold condition” is BigchainDB-specific (i.e. not part of the Interledger specs). It should only be used in combination with a timeout condition. - -When one creates a condition, one can calculate its fulfillment length (e.g. 96). The more complex the condition, the larger its fulfillment length will be. A BigchainDB federation can put an upper limit on the allowed fulfillment length, as a way of capping the complexity of conditions (and the computing time required to validate them). - -If someone tries to make a condition where the output of a threshold condition feeds into the input of another “earlier” threshold condition (i.e. in a closed logical circuit), then their computer will take forever to calculate the (infinite) “condition URI”, at least in theory. In practice, their computer will run out of memory or their client software will timeout after a while. - -Aside: In what follows, the list of `owners_after` (in a condition) is always who owned the asset at the time the transaction completed, but before the next transaction started. The list of `owners_before` (in a fulfillment) is always equal to the list of `owners_after` in that asset's previous transaction. - -### Conditions - -#### One New Owner - -If there is only one _new owner_, the condition will be a simple signature condition (i.e. only one signature is required). - -```json -{ - "cid": "", - "condition": { - "details": { - "bitmask": "", - "public_key": "", - "signature": null, - "type": "fulfillment", - "type_id": "" - }, - "uri": "" - }, - "owners_after": [""], - "amount": "" -} -``` - -- **Condition header**: - - `cid`: Condition index so that we can reference this output as an input to another transaction. It also matches - the input `fid`, making this the condition to fulfill in order to spend the asset used as input with `fid`. - - `owners_after`: A list containing one item: the public key of the new owner. - - `amount`: The amount of shares for a divisible asset to send to the new owners. -- **Condition body**: - - `bitmask`: A set of bits representing the features required by the condition type. - - `public_key`: The new owner's public key. - - `type_id`: The fulfillment type ID; see the [ILP spec](https://interledger.org/five-bells-condition/spec.html). - - `uri`: Binary representation of the condition using only URL-safe characters. - -#### Multiple New Owners - -If there are multiple _new owners_, they can create a ThresholdCondition requiring a signature from each of them in order -to spend the asset. For example: - -```json -{ - "cid": "", - "condition": { - "details": { - "bitmask": 41, - "subfulfillments": [ - { - "bitmask": 32, - "public_key": "", - "signature": null, - "type": "fulfillment", - "type_id": 4, - "weight": 1 - }, - { - "bitmask": 32, - "public_key": "", - "signature": null, - "type": "fulfillment", - "type_id": 4, - "weight": 1 - } - ], - "threshold": 2, - "type": "fulfillment", - "type_id": 2 - }, - "uri": "cc:2:29:ytNK3X6-bZsbF-nCGDTuopUIMi1HCyCkyPewm6oLI3o:206"}, - "owners_after": [ - "owner 1 public key>", - "owner 2 public key>" - ] -} -``` - -- `subfulfillments`: a list of fulfillments - - `weight`: integer weight for each subfulfillment's contribution to the threshold -- `threshold`: threshold to reach for the subfulfillments to reach a valid fulfillment - -The `weight`s and `threshold` could be adjusted. For example, if the `threshold` was changed to 1 above, then only one of the new owners would have to provide a signature to spend the asset. - -### Fulfillments - -#### One Current Owner - -If there is only one _current owner_, the fulfillment will be a simple signature fulfillment (i.e. containing just one signature). - -```json -{ - "owners_before": [""], - "fid": 0, - "fulfillment": "cf:4:RxFzIE679tFBk8zwEgizhmTuciAylvTUwy6EL6ehddHFJOhK5F4IjwQ1xLu2oQK9iyRCZJdfWAefZVjTt3DeG5j2exqxpGliOPYseNkRAWEakqJ_UrCwgnj92dnFRAEE", - "input": { - "cid": 0, - "txid": "11b3e7d893cc5fdfcf1a1706809c7def290a3b10b0bef6525d10b024649c42d3" - } -} -``` - -- `fid`: Fulfillment index. It matches a `cid` in the conditions with a new _crypto-condition_ that the new owner - needs to fulfill to spend this asset. -- `owners_before`: A list of public keys of the owners before the transaction; in this case it has just one public key. -- `fulfillment`: A crypto-conditions URI that encodes the cryptographic fulfillments like signatures and others, see [crypto-conditions](https://interledger.org/five-bells-condition/spec.html). -- `input`: Pointer to the asset and condition of a previous transaction - - `cid`: Condition index - - `txid`: Transaction id - -## The Block Model - -```json -{ - "id": "", - "block": { - "timestamp": "", - "transactions": [""], - "node_pubkey": "", - "voters": [""] - }, - "signature": "", -} -``` - -- `id`: The hash of the serialized `block` (i.e. the `timestamp`, `transactions`, `node_pubkey`, and `voters`). This is also a database primary key; that's how we ensure that all blocks are unique. -- `block`: - - `timestamp`: The Unix time when the block was created. It's provided by the node that created the block. See [the section on timestamps](timestamps.html). - - `transactions`: A list of the transactions included in the block. - - `node_pubkey`: The public key of the node that create the block. - - `voters`: A list of public keys of federation nodes. Since the size of the - federation may change over time, this will tell us how many nodes existed - in the federation when the block was created, so that at a later point in - time we can check that the block received the correct number of votes. -- `signature`: Signature of the block by the node that created the block. (To create the signature, the node serializes the block contents and signs that with its private key.) - -## The Vote Model - -Each node must generate a vote for each block, to be appended the `votes` table. A vote has the following structure: - -```json -{ - "id": "", - "node_pubkey": "", - "vote": { - "voting_for_block": "", - "previous_block": "", - "is_block_valid": "", - "invalid_reason": "" - }, - "signature": "", -} -``` - -Note: The `invalid_reason` was not being used as of v0.1.3 and may be dropped in a future version of BigchainDB. +This page about the data models was getting too big, so it was split into smaller pages. It will be deleted eventually, so update your links. The new pages about the data models can now be found in [the Data Models section of the root BigchainDB docs](https://docs.bigchaindb.com/en/latest/data-models/index.html). From fc84e177a88893de5c7d469da046d1fa3ac4ba85 Mon Sep 17 00:00:00 2001 From: troymc Date: Sun, 23 Oct 2016 17:27:55 +0200 Subject: [PATCH 02/13] Added link to the new Transactions page as well --- docs/source/topic-guides/models.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/source/topic-guides/models.md b/docs/source/topic-guides/models.md index a443e51a..64e22d84 100644 --- a/docs/source/topic-guides/models.md +++ b/docs/source/topic-guides/models.md @@ -1,3 +1,6 @@ # The Transaction, Block and Vote Models -This page about the data models was getting too big, so it was split into smaller pages. It will be deleted eventually, so update your links. The new pages about the data models can now be found in [the Data Models section of the root BigchainDB docs](https://docs.bigchaindb.com/en/latest/data-models/index.html). +This page about the data models was getting too big, so it was split into smaller pages. It will be deleted eventually, so update your links. Here's where you can find the new pages: + +* [Transaction concepts](https://docs.bigchaindb.com/en/latest/transactions.html) +* [Data Models (all of them)](https://docs.bigchaindb.com/en/latest/data-models/index.html) From 2dd9249f21391c5600e1e11c29800441cd4d7aa6 Mon Sep 17 00:00:00 2001 From: Sylvain Bellemare Date: Wed, 26 Oct 2016 12:28:31 +0200 Subject: [PATCH 03/13] Add __init__.py files somehow find_packages does not seem to be able to find the package, although it should not be the case for > 3.2; see docs: > On Python 3.2 and earlier, packages are only recognized if they > include an __init__.py file. http://setuptools.readthedocs.io/en/latest/setuptools.html#using-find-packages --- bigchaindb/common/__init__.py | 0 tests/common/__init__.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 bigchaindb/common/__init__.py create mode 100644 tests/common/__init__.py diff --git a/bigchaindb/common/__init__.py b/bigchaindb/common/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/common/__init__.py b/tests/common/__init__.py new file mode 100644 index 00000000..e69de29b From d93f6f873b5d3b242da2b1c8a9c5474e19f4bd6a Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Wed, 26 Oct 2016 17:35:48 +0200 Subject: [PATCH 04/13] Update outdated or incorrect docstrings (#748) --- bigchaindb/commands/utils.py | 9 ++------- bigchaindb/core.py | 20 ++++++++++---------- bigchaindb/pipelines/stale.py | 4 ++-- bigchaindb/pipelines/utils.py | 18 +++++++++--------- bigchaindb/util.py | 2 +- 5 files changed, 24 insertions(+), 29 deletions(-) diff --git a/bigchaindb/commands/utils.py b/bigchaindb/commands/utils.py index 65459737..6619da6d 100644 --- a/bigchaindb/commands/utils.py +++ b/bigchaindb/commands/utils.py @@ -19,14 +19,9 @@ def start_rethinkdb(): """Start RethinkDB as a child process and wait for it to be available. - Args: - wait_for_db (bool): wait for the database to be ready - extra_opts (list): a list of extra options to be used when - starting the db - Raises: - ``bigchaindb.common.exceptions.StartupError`` if RethinkDB cannot - be started. + :class:`~bigchaindb.common.exceptions.StartupError` if + RethinkDB cannot be started. """ proc = subprocess.Popen(['rethinkdb', '--bind', 'all'], diff --git a/bigchaindb/core.py b/bigchaindb/core.py index 2724080f..83b85652 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -198,10 +198,10 @@ class Bigchain(object): the return value is then a tuple: (tx, status) Returns: - A dict with the transaction details if the transaction was found. - Will add the transaction status to payload ('valid', 'undecided', - or 'backlog'). If no transaction with that `txid` was found it - returns `None` + A :class:`~.models.Transaction` instance if the transaction + was found, otherwise ``None``. + If :attr:`include_status` is ``True``, also returns the + transaction's status if the transaction was found. """ response, tx_status = None, None @@ -412,14 +412,14 @@ class Bigchain(object): return None def get_owned_ids(self, owner): - """Retrieve a list of `txids` that can we used has inputs. + """Retrieve a list of `txid`s that can be used as inputs. Args: owner (str): base58 encoded public key. Returns: - list (TransactionLink): list of `txid`s and `cid`s pointing to - another transaction's condition + :obj:`list` of TransactionLink: list of `txid`s and `cid`s + pointing to another transaction's condition """ # get all transactions in which owner is in the `owners_after` list @@ -587,11 +587,11 @@ class Bigchain(object): return block def vote(self, block_id, previous_block_id, decision, invalid_reason=None): - """Cast your vote on the block given the previous_block_hash and the decision (valid/invalid) - return the block to the updated in the database. + """Create a signed vote for a block given the + :attr:`previous_block_id` and the :attr:`decision` (valid/invalid). Args: - block_id (str): The id of the block to vote. + block_id (str): The id of the block to vote on. previous_block_id (str): The id of the previous block. decision (bool): Whether the block is valid or invalid. invalid_reason (Optional[str]): Reason the block is invalid diff --git a/bigchaindb/pipelines/stale.py b/bigchaindb/pipelines/stale.py index 647ad2ae..cdc74aa6 100644 --- a/bigchaindb/pipelines/stale.py +++ b/bigchaindb/pipelines/stale.py @@ -26,8 +26,8 @@ class StaleTransactionMonitor: Args: timeout: how often to check for stale tx (in sec) backlog_reassign_delay: How stale a transaction should - be before reassignment (in sec). If supplied, overrides the - Bigchain default value. + be before reassignment (in sec). If supplied, overrides + the Bigchain default value. """ self.bigchain = Bigchain(backlog_reassign_delay=backlog_reassign_delay) self.timeout = timeout diff --git a/bigchaindb/pipelines/utils.py b/bigchaindb/pipelines/utils.py index 0a8dbcd1..26984500 100644 --- a/bigchaindb/pipelines/utils.py +++ b/bigchaindb/pipelines/utils.py @@ -13,16 +13,16 @@ logger = logging.getLogger(__name__) class ChangeFeed(Node): - """This class wraps a RethinkDB changefeed adding a `prefeed`. + """This class wraps a RethinkDB changefeed adding a ``prefeed``. - It extends the ``multipipes::Node`` class to make it pluggable in - other Pipelines instances, and it makes usage of ``self.outqueue`` - to output the data. + It extends :class:`multipipes.Node` to make it pluggable in other + Pipelines instances, and makes usage of ``self.outqueue`` to output + the data. A changefeed is a real time feed on inserts, updates, and deletes, and - it's volatile. This class is a helper to create changefeeds. Moreover - it provides a way to specify a `prefeed`, that is a set of data (iterable) - to output before the actual changefeed. + is volatile. This class is a helper to create changefeeds. Moreover, + it provides a way to specify a ``prefeed`` of iterable data to output + before the actual changefeed. """ INSERT = 1 @@ -35,8 +35,8 @@ class ChangeFeed(Node): Args: table (str): name of the table to listen to for changes. operation (int): can be ChangeFeed.INSERT, ChangeFeed.DELETE, or - ChangeFeed.UPDATE. Combining multiple operation is possible using - the bitwise ``|`` operator + ChangeFeed.UPDATE. Combining multiple operation is possible + with the bitwise ``|`` operator (e.g. ``ChangeFeed.INSERT | ChangeFeed.UPDATE``) prefeed (iterable): whatever set of data you want to be published first. diff --git a/bigchaindb/util.py b/bigchaindb/util.py index fcaa5e00..272c7d67 100644 --- a/bigchaindb/util.py +++ b/bigchaindb/util.py @@ -119,7 +119,7 @@ def condition_details_has_owner(condition_details, owner): def verify_vote_signature(voters, signed_vote): """Verify the signature of a vote - A valid vote should have been signed `owner_before` corresponding private key. + A valid vote should have been signed by a voter's private key. Args: voters (list): voters of the block that is under election From 6245b8cef43ba01ec4d483bf4ac5f7aaff1dde45 Mon Sep 17 00:00:00 2001 From: Sylvain Bellemare Date: Thu, 27 Oct 2016 10:39:45 +0200 Subject: [PATCH 05/13] Update version to 0.7.0.dev --- bigchaindb/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bigchaindb/version.py b/bigchaindb/version.py index e3155206..569af116 100644 --- a/bigchaindb/version.py +++ b/bigchaindb/version.py @@ -1,2 +1,2 @@ -__version__ = '0.6.0' -__short_version__ = '0.6' +__version__ = '0.7.0.dev' +__short_version__ = '0.7.dev' From cd2fd494ac3529aacfa82f1186e0a8ace20101ab Mon Sep 17 00:00:00 2001 From: troymc Date: Thu, 27 Oct 2016 14:09:24 +0200 Subject: [PATCH 06/13] Moved docs directory to docs/server, except README.md --- docs/{ => server}/Makefile | 0 docs/{ => server}/make.bat | 0 docs/{ => server}/requirements.txt | 0 .../{ => server}/source/_static/Node-components.png | Bin .../source/_static/cc_escrow_execute_abort.png | Bin docs/{ => server}/source/_static/cloud9.pdf | Bin .../{ => server}/source/_static/models_diagrams.odg | Bin .../source/_static/monitoring_system_diagram.png | Bin .../source/_static/stories_3_assets.png | Bin .../source/_static/tx_escrow_execute_abort.png | Bin .../tx_multi_condition_multi_fulfillment_v1.png | Bin docs/{ => server}/source/_static/tx_schematics.odg | Bin .../tx_single_condition_single_fulfillment_v1.png | Bin docs/{ => server}/source/appendices/aws-setup.md | 0 docs/{ => server}/source/appendices/consensus.rst | 0 docs/{ => server}/source/appendices/cryptography.md | 0 .../appendices/example-rethinkdb-storage-setups.md | 0 .../source/appendices/firewall-notes.md | 0 docs/{ => server}/source/appendices/index.rst | 0 .../source/appendices/install-latest-pip.md | 0 .../source/appendices/install-os-level-deps.md | 0 .../source/appendices/install-with-lxd.md | 0 .../source/appendices/json-serialization.md | 0 docs/{ => server}/source/appendices/licenses.md | 0 docs/{ => server}/source/appendices/ntp-notes.md | 0 docs/{ => server}/source/appendices/pipelines.rst | 0 .../source/appendices/run-with-docker.md | 0 .../source/appendices/the-Bigchain-class.rst | 0 .../cloud-deployment-starter-templates/index.rst | 0 .../template-ansible.md | 0 .../template-azure.md | 0 .../template-terraform-aws.md | 0 .../source/clusters-feds/aws-testing-cluster.md | 0 docs/{ => server}/source/clusters-feds/backup.md | 0 docs/{ => server}/source/clusters-feds/index.rst | 0 .../{ => server}/source/clusters-feds/monitoring.md | 0 .../source/clusters-feds/set-up-a-federation.md | 0 docs/{ => server}/source/conf.py | 0 docs/{ => server}/source/dev-and-test/index.rst | 0 .../source/dev-and-test/running-unit-tests.md | 0 .../source/dev-and-test/setup-run-node.md | 0 .../source/drivers-clients/example-apps.rst | 0 .../drivers-clients/http-client-server-api.rst | 0 docs/{ => server}/source/drivers-clients/index.rst | 0 .../source/drivers-clients/python-driver.md | 0 .../drivers-clients/python-server-api-examples.md | 0 docs/{ => server}/source/index.rst | 0 docs/{ => server}/source/introduction.md | 0 docs/{ => server}/source/nodes/index.rst | 0 docs/{ => server}/source/nodes/node-assumptions.md | 0 docs/{ => server}/source/nodes/node-components.md | 0 docs/{ => server}/source/nodes/node-requirements.md | 0 docs/{ => server}/source/nodes/setup-run-node.md | 0 docs/{ => server}/source/quickstart.md | 0 docs/{ => server}/source/release-notes.md | 0 .../source/server-reference/bigchaindb-cli.md | 0 .../source/server-reference/configuration.md | 0 docs/{ => server}/source/server-reference/index.rst | 0 docs/{ => server}/source/topic-guides/index.rst | 0 docs/{ => server}/source/topic-guides/models.md | 0 60 files changed, 0 insertions(+), 0 deletions(-) rename docs/{ => server}/Makefile (100%) rename docs/{ => server}/make.bat (100%) rename docs/{ => server}/requirements.txt (100%) rename docs/{ => server}/source/_static/Node-components.png (100%) rename docs/{ => server}/source/_static/cc_escrow_execute_abort.png (100%) rename docs/{ => server}/source/_static/cloud9.pdf (100%) rename docs/{ => server}/source/_static/models_diagrams.odg (100%) rename docs/{ => server}/source/_static/monitoring_system_diagram.png (100%) rename docs/{ => server}/source/_static/stories_3_assets.png (100%) rename docs/{ => server}/source/_static/tx_escrow_execute_abort.png (100%) rename docs/{ => server}/source/_static/tx_multi_condition_multi_fulfillment_v1.png (100%) rename docs/{ => server}/source/_static/tx_schematics.odg (100%) rename docs/{ => server}/source/_static/tx_single_condition_single_fulfillment_v1.png (100%) rename docs/{ => server}/source/appendices/aws-setup.md (100%) rename docs/{ => server}/source/appendices/consensus.rst (100%) rename docs/{ => server}/source/appendices/cryptography.md (100%) rename docs/{ => server}/source/appendices/example-rethinkdb-storage-setups.md (100%) rename docs/{ => server}/source/appendices/firewall-notes.md (100%) rename docs/{ => server}/source/appendices/index.rst (100%) rename docs/{ => server}/source/appendices/install-latest-pip.md (100%) rename docs/{ => server}/source/appendices/install-os-level-deps.md (100%) rename docs/{ => server}/source/appendices/install-with-lxd.md (100%) rename docs/{ => server}/source/appendices/json-serialization.md (100%) rename docs/{ => server}/source/appendices/licenses.md (100%) rename docs/{ => server}/source/appendices/ntp-notes.md (100%) rename docs/{ => server}/source/appendices/pipelines.rst (100%) rename docs/{ => server}/source/appendices/run-with-docker.md (100%) rename docs/{ => server}/source/appendices/the-Bigchain-class.rst (100%) rename docs/{ => server}/source/cloud-deployment-starter-templates/index.rst (100%) rename docs/{ => server}/source/cloud-deployment-starter-templates/template-ansible.md (100%) rename docs/{ => server}/source/cloud-deployment-starter-templates/template-azure.md (100%) rename docs/{ => server}/source/cloud-deployment-starter-templates/template-terraform-aws.md (100%) rename docs/{ => server}/source/clusters-feds/aws-testing-cluster.md (100%) rename docs/{ => server}/source/clusters-feds/backup.md (100%) rename docs/{ => server}/source/clusters-feds/index.rst (100%) rename docs/{ => server}/source/clusters-feds/monitoring.md (100%) rename docs/{ => server}/source/clusters-feds/set-up-a-federation.md (100%) rename docs/{ => server}/source/conf.py (100%) rename docs/{ => server}/source/dev-and-test/index.rst (100%) rename docs/{ => server}/source/dev-and-test/running-unit-tests.md (100%) rename docs/{ => server}/source/dev-and-test/setup-run-node.md (100%) rename docs/{ => server}/source/drivers-clients/example-apps.rst (100%) rename docs/{ => server}/source/drivers-clients/http-client-server-api.rst (100%) rename docs/{ => server}/source/drivers-clients/index.rst (100%) rename docs/{ => server}/source/drivers-clients/python-driver.md (100%) rename docs/{ => server}/source/drivers-clients/python-server-api-examples.md (100%) rename docs/{ => server}/source/index.rst (100%) rename docs/{ => server}/source/introduction.md (100%) rename docs/{ => server}/source/nodes/index.rst (100%) rename docs/{ => server}/source/nodes/node-assumptions.md (100%) rename docs/{ => server}/source/nodes/node-components.md (100%) rename docs/{ => server}/source/nodes/node-requirements.md (100%) rename docs/{ => server}/source/nodes/setup-run-node.md (100%) rename docs/{ => server}/source/quickstart.md (100%) rename docs/{ => server}/source/release-notes.md (100%) rename docs/{ => server}/source/server-reference/bigchaindb-cli.md (100%) rename docs/{ => server}/source/server-reference/configuration.md (100%) rename docs/{ => server}/source/server-reference/index.rst (100%) rename docs/{ => server}/source/topic-guides/index.rst (100%) rename docs/{ => server}/source/topic-guides/models.md (100%) diff --git a/docs/Makefile b/docs/server/Makefile similarity index 100% rename from docs/Makefile rename to docs/server/Makefile diff --git a/docs/make.bat b/docs/server/make.bat similarity index 100% rename from docs/make.bat rename to docs/server/make.bat diff --git a/docs/requirements.txt b/docs/server/requirements.txt similarity index 100% rename from docs/requirements.txt rename to docs/server/requirements.txt diff --git a/docs/source/_static/Node-components.png b/docs/server/source/_static/Node-components.png similarity index 100% rename from docs/source/_static/Node-components.png rename to docs/server/source/_static/Node-components.png diff --git a/docs/source/_static/cc_escrow_execute_abort.png b/docs/server/source/_static/cc_escrow_execute_abort.png similarity index 100% rename from docs/source/_static/cc_escrow_execute_abort.png rename to docs/server/source/_static/cc_escrow_execute_abort.png diff --git a/docs/source/_static/cloud9.pdf b/docs/server/source/_static/cloud9.pdf similarity index 100% rename from docs/source/_static/cloud9.pdf rename to docs/server/source/_static/cloud9.pdf diff --git a/docs/source/_static/models_diagrams.odg b/docs/server/source/_static/models_diagrams.odg similarity index 100% rename from docs/source/_static/models_diagrams.odg rename to docs/server/source/_static/models_diagrams.odg diff --git a/docs/source/_static/monitoring_system_diagram.png b/docs/server/source/_static/monitoring_system_diagram.png similarity index 100% rename from docs/source/_static/monitoring_system_diagram.png rename to docs/server/source/_static/monitoring_system_diagram.png diff --git a/docs/source/_static/stories_3_assets.png b/docs/server/source/_static/stories_3_assets.png similarity index 100% rename from docs/source/_static/stories_3_assets.png rename to docs/server/source/_static/stories_3_assets.png diff --git a/docs/source/_static/tx_escrow_execute_abort.png b/docs/server/source/_static/tx_escrow_execute_abort.png similarity index 100% rename from docs/source/_static/tx_escrow_execute_abort.png rename to docs/server/source/_static/tx_escrow_execute_abort.png diff --git a/docs/source/_static/tx_multi_condition_multi_fulfillment_v1.png b/docs/server/source/_static/tx_multi_condition_multi_fulfillment_v1.png similarity index 100% rename from docs/source/_static/tx_multi_condition_multi_fulfillment_v1.png rename to docs/server/source/_static/tx_multi_condition_multi_fulfillment_v1.png diff --git a/docs/source/_static/tx_schematics.odg b/docs/server/source/_static/tx_schematics.odg similarity index 100% rename from docs/source/_static/tx_schematics.odg rename to docs/server/source/_static/tx_schematics.odg diff --git a/docs/source/_static/tx_single_condition_single_fulfillment_v1.png b/docs/server/source/_static/tx_single_condition_single_fulfillment_v1.png similarity index 100% rename from docs/source/_static/tx_single_condition_single_fulfillment_v1.png rename to docs/server/source/_static/tx_single_condition_single_fulfillment_v1.png diff --git a/docs/source/appendices/aws-setup.md b/docs/server/source/appendices/aws-setup.md similarity index 100% rename from docs/source/appendices/aws-setup.md rename to docs/server/source/appendices/aws-setup.md diff --git a/docs/source/appendices/consensus.rst b/docs/server/source/appendices/consensus.rst similarity index 100% rename from docs/source/appendices/consensus.rst rename to docs/server/source/appendices/consensus.rst diff --git a/docs/source/appendices/cryptography.md b/docs/server/source/appendices/cryptography.md similarity index 100% rename from docs/source/appendices/cryptography.md rename to docs/server/source/appendices/cryptography.md diff --git a/docs/source/appendices/example-rethinkdb-storage-setups.md b/docs/server/source/appendices/example-rethinkdb-storage-setups.md similarity index 100% rename from docs/source/appendices/example-rethinkdb-storage-setups.md rename to docs/server/source/appendices/example-rethinkdb-storage-setups.md diff --git a/docs/source/appendices/firewall-notes.md b/docs/server/source/appendices/firewall-notes.md similarity index 100% rename from docs/source/appendices/firewall-notes.md rename to docs/server/source/appendices/firewall-notes.md diff --git a/docs/source/appendices/index.rst b/docs/server/source/appendices/index.rst similarity index 100% rename from docs/source/appendices/index.rst rename to docs/server/source/appendices/index.rst diff --git a/docs/source/appendices/install-latest-pip.md b/docs/server/source/appendices/install-latest-pip.md similarity index 100% rename from docs/source/appendices/install-latest-pip.md rename to docs/server/source/appendices/install-latest-pip.md diff --git a/docs/source/appendices/install-os-level-deps.md b/docs/server/source/appendices/install-os-level-deps.md similarity index 100% rename from docs/source/appendices/install-os-level-deps.md rename to docs/server/source/appendices/install-os-level-deps.md diff --git a/docs/source/appendices/install-with-lxd.md b/docs/server/source/appendices/install-with-lxd.md similarity index 100% rename from docs/source/appendices/install-with-lxd.md rename to docs/server/source/appendices/install-with-lxd.md diff --git a/docs/source/appendices/json-serialization.md b/docs/server/source/appendices/json-serialization.md similarity index 100% rename from docs/source/appendices/json-serialization.md rename to docs/server/source/appendices/json-serialization.md diff --git a/docs/source/appendices/licenses.md b/docs/server/source/appendices/licenses.md similarity index 100% rename from docs/source/appendices/licenses.md rename to docs/server/source/appendices/licenses.md diff --git a/docs/source/appendices/ntp-notes.md b/docs/server/source/appendices/ntp-notes.md similarity index 100% rename from docs/source/appendices/ntp-notes.md rename to docs/server/source/appendices/ntp-notes.md diff --git a/docs/source/appendices/pipelines.rst b/docs/server/source/appendices/pipelines.rst similarity index 100% rename from docs/source/appendices/pipelines.rst rename to docs/server/source/appendices/pipelines.rst diff --git a/docs/source/appendices/run-with-docker.md b/docs/server/source/appendices/run-with-docker.md similarity index 100% rename from docs/source/appendices/run-with-docker.md rename to docs/server/source/appendices/run-with-docker.md diff --git a/docs/source/appendices/the-Bigchain-class.rst b/docs/server/source/appendices/the-Bigchain-class.rst similarity index 100% rename from docs/source/appendices/the-Bigchain-class.rst rename to docs/server/source/appendices/the-Bigchain-class.rst diff --git a/docs/source/cloud-deployment-starter-templates/index.rst b/docs/server/source/cloud-deployment-starter-templates/index.rst similarity index 100% rename from docs/source/cloud-deployment-starter-templates/index.rst rename to docs/server/source/cloud-deployment-starter-templates/index.rst diff --git a/docs/source/cloud-deployment-starter-templates/template-ansible.md b/docs/server/source/cloud-deployment-starter-templates/template-ansible.md similarity index 100% rename from docs/source/cloud-deployment-starter-templates/template-ansible.md rename to docs/server/source/cloud-deployment-starter-templates/template-ansible.md diff --git a/docs/source/cloud-deployment-starter-templates/template-azure.md b/docs/server/source/cloud-deployment-starter-templates/template-azure.md similarity index 100% rename from docs/source/cloud-deployment-starter-templates/template-azure.md rename to docs/server/source/cloud-deployment-starter-templates/template-azure.md diff --git a/docs/source/cloud-deployment-starter-templates/template-terraform-aws.md b/docs/server/source/cloud-deployment-starter-templates/template-terraform-aws.md similarity index 100% rename from docs/source/cloud-deployment-starter-templates/template-terraform-aws.md rename to docs/server/source/cloud-deployment-starter-templates/template-terraform-aws.md diff --git a/docs/source/clusters-feds/aws-testing-cluster.md b/docs/server/source/clusters-feds/aws-testing-cluster.md similarity index 100% rename from docs/source/clusters-feds/aws-testing-cluster.md rename to docs/server/source/clusters-feds/aws-testing-cluster.md diff --git a/docs/source/clusters-feds/backup.md b/docs/server/source/clusters-feds/backup.md similarity index 100% rename from docs/source/clusters-feds/backup.md rename to docs/server/source/clusters-feds/backup.md diff --git a/docs/source/clusters-feds/index.rst b/docs/server/source/clusters-feds/index.rst similarity index 100% rename from docs/source/clusters-feds/index.rst rename to docs/server/source/clusters-feds/index.rst diff --git a/docs/source/clusters-feds/monitoring.md b/docs/server/source/clusters-feds/monitoring.md similarity index 100% rename from docs/source/clusters-feds/monitoring.md rename to docs/server/source/clusters-feds/monitoring.md diff --git a/docs/source/clusters-feds/set-up-a-federation.md b/docs/server/source/clusters-feds/set-up-a-federation.md similarity index 100% rename from docs/source/clusters-feds/set-up-a-federation.md rename to docs/server/source/clusters-feds/set-up-a-federation.md diff --git a/docs/source/conf.py b/docs/server/source/conf.py similarity index 100% rename from docs/source/conf.py rename to docs/server/source/conf.py diff --git a/docs/source/dev-and-test/index.rst b/docs/server/source/dev-and-test/index.rst similarity index 100% rename from docs/source/dev-and-test/index.rst rename to docs/server/source/dev-and-test/index.rst diff --git a/docs/source/dev-and-test/running-unit-tests.md b/docs/server/source/dev-and-test/running-unit-tests.md similarity index 100% rename from docs/source/dev-and-test/running-unit-tests.md rename to docs/server/source/dev-and-test/running-unit-tests.md diff --git a/docs/source/dev-and-test/setup-run-node.md b/docs/server/source/dev-and-test/setup-run-node.md similarity index 100% rename from docs/source/dev-and-test/setup-run-node.md rename to docs/server/source/dev-and-test/setup-run-node.md diff --git a/docs/source/drivers-clients/example-apps.rst b/docs/server/source/drivers-clients/example-apps.rst similarity index 100% rename from docs/source/drivers-clients/example-apps.rst rename to docs/server/source/drivers-clients/example-apps.rst diff --git a/docs/source/drivers-clients/http-client-server-api.rst b/docs/server/source/drivers-clients/http-client-server-api.rst similarity index 100% rename from docs/source/drivers-clients/http-client-server-api.rst rename to docs/server/source/drivers-clients/http-client-server-api.rst diff --git a/docs/source/drivers-clients/index.rst b/docs/server/source/drivers-clients/index.rst similarity index 100% rename from docs/source/drivers-clients/index.rst rename to docs/server/source/drivers-clients/index.rst diff --git a/docs/source/drivers-clients/python-driver.md b/docs/server/source/drivers-clients/python-driver.md similarity index 100% rename from docs/source/drivers-clients/python-driver.md rename to docs/server/source/drivers-clients/python-driver.md diff --git a/docs/source/drivers-clients/python-server-api-examples.md b/docs/server/source/drivers-clients/python-server-api-examples.md similarity index 100% rename from docs/source/drivers-clients/python-server-api-examples.md rename to docs/server/source/drivers-clients/python-server-api-examples.md diff --git a/docs/source/index.rst b/docs/server/source/index.rst similarity index 100% rename from docs/source/index.rst rename to docs/server/source/index.rst diff --git a/docs/source/introduction.md b/docs/server/source/introduction.md similarity index 100% rename from docs/source/introduction.md rename to docs/server/source/introduction.md diff --git a/docs/source/nodes/index.rst b/docs/server/source/nodes/index.rst similarity index 100% rename from docs/source/nodes/index.rst rename to docs/server/source/nodes/index.rst diff --git a/docs/source/nodes/node-assumptions.md b/docs/server/source/nodes/node-assumptions.md similarity index 100% rename from docs/source/nodes/node-assumptions.md rename to docs/server/source/nodes/node-assumptions.md diff --git a/docs/source/nodes/node-components.md b/docs/server/source/nodes/node-components.md similarity index 100% rename from docs/source/nodes/node-components.md rename to docs/server/source/nodes/node-components.md diff --git a/docs/source/nodes/node-requirements.md b/docs/server/source/nodes/node-requirements.md similarity index 100% rename from docs/source/nodes/node-requirements.md rename to docs/server/source/nodes/node-requirements.md diff --git a/docs/source/nodes/setup-run-node.md b/docs/server/source/nodes/setup-run-node.md similarity index 100% rename from docs/source/nodes/setup-run-node.md rename to docs/server/source/nodes/setup-run-node.md diff --git a/docs/source/quickstart.md b/docs/server/source/quickstart.md similarity index 100% rename from docs/source/quickstart.md rename to docs/server/source/quickstart.md diff --git a/docs/source/release-notes.md b/docs/server/source/release-notes.md similarity index 100% rename from docs/source/release-notes.md rename to docs/server/source/release-notes.md diff --git a/docs/source/server-reference/bigchaindb-cli.md b/docs/server/source/server-reference/bigchaindb-cli.md similarity index 100% rename from docs/source/server-reference/bigchaindb-cli.md rename to docs/server/source/server-reference/bigchaindb-cli.md diff --git a/docs/source/server-reference/configuration.md b/docs/server/source/server-reference/configuration.md similarity index 100% rename from docs/source/server-reference/configuration.md rename to docs/server/source/server-reference/configuration.md diff --git a/docs/source/server-reference/index.rst b/docs/server/source/server-reference/index.rst similarity index 100% rename from docs/source/server-reference/index.rst rename to docs/server/source/server-reference/index.rst diff --git a/docs/source/topic-guides/index.rst b/docs/server/source/topic-guides/index.rst similarity index 100% rename from docs/source/topic-guides/index.rst rename to docs/server/source/topic-guides/index.rst diff --git a/docs/source/topic-guides/models.md b/docs/server/source/topic-guides/models.md similarity index 100% rename from docs/source/topic-guides/models.md rename to docs/server/source/topic-guides/models.md From 61eed2f91e422db577b8dca6fc4efcd2343113a7 Mon Sep 17 00:00:00 2001 From: troymc Date: Thu, 27 Oct 2016 14:09:55 +0200 Subject: [PATCH 07/13] Updated docs/README.md --- docs/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 15879adc..5169f871 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,12 +10,14 @@ # How to Generate the HTML Version of the Long-Form Documentation -If you want to generate the HTML version of the long-form documentation on your local machine, you need to have Sphinx and some Sphinx-contrib packages installed. To do that, go to the BigchainDB `docs` directory (i.e. this directory) and do: +If you want to generate the HTML version of the long-form documentation on your local machine, you need to have Sphinx and some Sphinx-contrib packages installed. To do that, go to a subdirectory of `docs` (e.g. `docs/server`) and do: ```bash pip install -r requirements.txt ``` -You can then generate the HTML documentation by doing: + +You can then generate the HTML documentation _in that subdirectory_ by doing: ```bash make html ``` -The generated HTML documentation will be in the `docs/build/html` directory. You can view it by opening `docs/build/html/index.html` in your web browser. + +It should tell you where the generated documentation (HTML files) can be found. You can view it in your web browser. From d2d9539e4c60c17733ec4905058612af77549cf6 Mon Sep 17 00:00:00 2001 From: troymc Date: Thu, 27 Oct 2016 14:17:16 +0200 Subject: [PATCH 08/13] Updated path to version.py in docs/server/source/conf.py --- docs/server/source/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/server/source/conf.py b/docs/server/source/conf.py index e429154c..640e3273 100644 --- a/docs/server/source/conf.py +++ b/docs/server/source/conf.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# BigchainDB documentation build configuration file, created by +# BigchainDB Server documentation build configuration file, created by # sphinx-quickstart on Tue Jan 19 14:42:58 2016. # # This file is execfile()d with the current directory set to its @@ -32,7 +32,7 @@ import sphinx_rtd_theme # get version _version = {} -with open('../../bigchaindb/version.py') as fp: +with open('../../../bigchaindb/version.py') as fp: exec(fp.read(), _version) From a52921e9ec05b77df1645c2a48fb21d36b969044 Mon Sep 17 00:00:00 2001 From: troymc Date: Thu, 27 Oct 2016 18:45:11 +0200 Subject: [PATCH 09/13] Updated the docs page about the HTTP API --- .../http-client-server-api.rst | 345 +++++++++--------- 1 file changed, 168 insertions(+), 177 deletions(-) diff --git a/docs/server/source/drivers-clients/http-client-server-api.rst b/docs/server/source/drivers-clients/http-client-server-api.rst index dc7cd54b..74bcf1d2 100644 --- a/docs/server/source/drivers-clients/http-client-server-api.rst +++ b/docs/server/source/drivers-clients/http-client-server-api.rst @@ -1,7 +1,9 @@ The HTTP Client-Server API ========================== -Note: The HTTP client-server API is currently quite rudimentary. For example, there is no ability to do complex queries using the HTTP API. We plan to add querying capabilities in the future. +.. note:: + + The HTTP client-server API is currently quite rudimentary. For example, there is no ability to do complex queries using the HTTP API. We plan to add querying capabilities in the future. When you start Bigchaindb using `bigchaindb start`, an HTTP API is exposed at the address stored in the BigchainDB node configuration settings. The default is: @@ -11,6 +13,10 @@ but that address can be changed by changing the "API endpoint" configuration set There are other configuration settings related to the web server (serving the HTTP API). In particular, the default is for the web server socket to bind to ``localhost:9984`` but that can be changed (e.g. to ``0.0.0.0:9984``). For more details, see the "server" settings ("bind", "workers" and "threads") in :doc:`the section about BigchainDB Configuration Settings <../server-reference/configuration>`. + +API Root +-------- + If you send an HTTP GET request to e.g. ``http://localhost:9984`` (with no ``/api/v1/`` on the end), then you should get an HTTP response with something like the following in the body: .. code-block:: json @@ -27,87 +33,134 @@ If you send an HTTP GET request to e.g. ``http://localhost:9984`` (with no ``/ap } -HTTP API Endpoints ------------------- +POST /transactions/ +------------------- -.. http:get:: /transactions/{tx_id} +.. http:post:: /transactions/ - Get the transaction with the ID ``tx_id``. - - This endpoint returns only a transaction from a ``VALID`` or ``UNDECIDED`` block on ``bigchain``, if exists. - - :param tx_id: transaction ID - :type tx_id: hex string + Push a new transaction. + + Note: The posted transaction should be valid `transaction `_. The steps to build a valid transaction are beyond the scope of this page. One would normally use a driver such as the `BigchainDB Python Driver `_ to build a valid transaction. **Example request**: .. sourcecode:: http - GET /transactions/7ad5a4b83bc8c70c4fd7420ff3c60693ab8e6d0e3124378ca69ed5acd2578792 HTTP/1.1 + POST /transactions/ HTTP/1.1 Host: example.com + Content-Type: application/json + + { + "transaction": { + "conditions": [ + { + "cid": 0, + "condition": { + "uri": "cc:4:20:GG-pi3CeIlySZhQoJVBh9O23PzrOuhnYI7OHqIbHjkk:96", + "details": { + "signature": null, + "type": "fulfillment", + "type_id": 4, + "bitmask": 32, + "public_key": "2ePYHfV3yS3xTxF9EE3Xjo8zPwq2RmLPFAJGQqQKc3j6" + } + }, + "amount": 1, + "owners_after": [ + "2ePYHfV3yS3xTxF9EE3Xjo8zPwq2RmLPFAJGQqQKc3j6" + ] + } + ], + "operation": "CREATE", + "asset": { + "divisible": false, + "updatable": false, + "data": null, + "id": "aebeab22-e672-4d3b-a187-bde5fda6533d", + "refillable": false + }, + "metadata": null, + "timestamp": "1477578978", + "fulfillments": [ + { + "fid": 0, + "input": null, + "fulfillment": "cf:4:GG-pi3CeIlySZhQoJVBh9O23PzrOuhnYI7OHqIbHjkn2VnQaEWvecO1x82Qr2Va_JjFywLKIOEV1Ob9Ofkeln2K89ny2mB-s7RLNvYAVzWNiQnp18_nQEUsvwACEXTYJ", + "owners_before": [ + "2ePYHfV3yS3xTxF9EE3Xjo8zPwq2RmLPFAJGQqQKc3j6" + ] + } + ] + }, + "id": "2d431073e1477f3073a4693ac7ff9be5634751de1b8abaa1f4e19548ef0b4b0e", + "version": 1 + } **Example response**: .. sourcecode:: http - HTTP/1.1 200 OK + HTTP/1.1 201 Created Content-Type: application/json { - "id":"7ad5a4b83bc8c70c4fd7420ff3c60693ab8e6d0e3124378ca69ed5acd2578792", - "transaction":{ - "conditions":[ - { - "cid":0, - "condition":{ - "details":{ - "bitmask":32, - "public_key":"CwA8s2QYQBfNz4WvjEwmJi83zYr7JhxRhidx6uZ5KBVd", - "signature":null, - "type":"fulfillment", - "type_id":4 - }, - "uri":"cc:4:20:sVA_3p8gvl8yRFNTomqm6MaavKewka6dGYcFAuPrRXQ:96" - }, - "owners_after":[ - "CwA8s2QYQBfNz4WvjEwmJi83zYr7JhxRhidx6uZ5KBVd" - ] + "id": "2d431073e1477f3073a4693ac7ff9be5634751de1b8abaa1f4e19548ef0b4b0e", + "version": 1, + "transaction": { + "conditions": [ + { + "amount": 1, + "condition": { + "uri": "cc:4:20:GG-pi3CeIlySZhQoJVBh9O23PzrOuhnYI7OHqIbHjkk:96", + "details": { + "signature": null, + "type_id": 4, + "type": "fulfillment", + "bitmask": 32, + "public_key": "2ePYHfV3yS3xTxF9EE3Xjo8zPwq2RmLPFAJGQqQKc3j6" } - ], - "data":{ - "payload":null, - "uuid":"a9999d69-6cde-4b80-819d-ed57f6abe257" - }, - "fulfillments":[ - { - "owners_before":[ - "JEAkEJqLbbgDRAtMm8YAjGp759Aq2qTn9eaEHUj2XePE" - ], - "fid":0, - "fulfillment":"cf:4:__Y_Um6H73iwPe6ejWXEw930SQhqVGjtAHTXilPp0P01vE_Cx6zs3GJVoO1jhPL18C94PIVkLTGMUB2aKC9qsbIb3w8ejpOf0_I3OCuTbPdkd6r2lKMeVftMyMxkeWoM", - "input":{ - "cid":0, - "txid":"598ce4e9a29837a1c6fc337ee4a41b61c20ad25d01646754c825b1116abd8761" - } - } - ], - "operation":"TRANSFER", - "timestamp":"1471423869", - "version":1 - } + }, + "owners_after": [ + "2ePYHfV3yS3xTxF9EE3Xjo8zPwq2RmLPFAJGQqQKc3j6" + ], + "cid": 0 + } + ], + "fulfillments": [ + { + "input": null, + "fulfillment": "cf:4:GG-pi3CeIlySZhQoJVBh9O23PzrOuhnYI7OHqIbHjkn2VnQaEWvecO1x82Qr2Va_JjFywLKIOEV1Ob9Ofkeln2K89ny2mB-s7RLNvYAVzWNiQnp18_nQEUsvwACEXTYJ", + "fid": 0, + "owners_before": [ + "2ePYHfV3yS3xTxF9EE3Xjo8zPwq2RmLPFAJGQqQKc3j6" + ] + } + ], + "operation": "CREATE", + "timestamp": "1477578978", + "asset": { + "updatable": false, + "refillable": false, + "divisible": false, + "data": null, + "id": "aebeab22-e672-4d3b-a187-bde5fda6533d" + }, + "metadata": null + } } - :statuscode 200: A transaction with that ID was found. - :statuscode 404: A transaction with that ID was not found. + :statuscode 201: A new transaction was created. + :statuscode 400: The transaction was invalid and not created. +GET /transactions/{tx_id}/status +-------------------------------- + .. http:get:: /transactions/{tx_id}/status - Get the status of a transaction with the ID ``tx_id``. + Get the status of the transaction with the ID ``tx_id``, if a transaction with that ``tx_id`` exists. - This endpoint returns the status of a transaction if exists. - - Possible values are ``valid``, ``invalid``, ``undecided`` or ``backlog``. + The possible status values are ``backlog``, ``undecided``, ``valid`` or ``invalid``. :param tx_id: transaction ID :type tx_id: hex string @@ -133,140 +186,78 @@ HTTP API Endpoints :statuscode 200: A transaction with that ID was found and the status is returned. :statuscode 404: A transaction with that ID was not found. -.. http:post:: /transactions/ - Push a new transaction. +GET /transactions/{tx_id} +------------------------- + +.. http:get:: /transactions/{tx_id} + + Get the transaction with the ID ``tx_id``. + + This endpoint returns only a transaction from a ``VALID`` or ``UNDECIDED`` block on ``bigchain``, if exists. + + :param tx_id: transaction ID + :type tx_id: hex string **Example request**: .. sourcecode:: http - POST /transactions/ HTTP/1.1 + GET /transactions/2d431073e1477f3073a4693ac7ff9be5634751de1b8abaa1f4e19548ef0b4b0e HTTP/1.1 Host: example.com - Content-Type: application/json - - { - "id":"7ad5a4b83bc8c70c4fd7420ff3c60693ab8e6d0e3124378ca69ed5acd2578792", - "transaction":{ - "conditions":[ - { - "cid":0, - "condition":{ - "details":{ - "bitmask":32, - "public_key":"CwA8s2QYQBfNz4WvjEwmJi83zYr7JhxRhidx6uZ5KBVd", - "signature":null, - "type":"fulfillment", - "type_id":4 - }, - "uri":"cc:4:20:sVA_3p8gvl8yRFNTomqm6MaavKewka6dGYcFAuPrRXQ:96" - }, - "owners_after":[ - "CwA8s2QYQBfNz4WvjEwmJi83zYr7JhxRhidx6uZ5KBVd" - ] - } - ], - "data":{ - "payload":null, - "uuid":"a9999d69-6cde-4b80-819d-ed57f6abe257" - }, - "fulfillments":[ - { - "owners_before":[ - "JEAkEJqLbbgDRAtMm8YAjGp759Aq2qTn9eaEHUj2XePE" - ], - "fid":0, - "fulfillment":"cf:4:__Y_Um6H73iwPe6ejWXEw930SQhqVGjtAHTXilPp0P01vE_Cx6zs3GJVoO1jhPL18C94PIVkLTGMUB2aKC9qsbIb3w8ejpOf0_I3OCuTbPdkd6r2lKMeVftMyMxkeWoM", - "input":{ - "cid":0, - "txid":"598ce4e9a29837a1c6fc337ee4a41b61c20ad25d01646754c825b1116abd8761" - } - } - ], - "operation":"TRANSFER", - "timestamp":"1471423869", - "version":1 - } - } **Example response**: .. sourcecode:: http - HTTP/1.1 201 Created + HTTP/1.1 200 OK Content-Type: application/json { - "assignee":"4XYfCbabAWVUCbjTmRTFEu2sc3dFEdkse4r6X498B1s8", - "id":"7ad5a4b83bc8c70c4fd7420ff3c60693ab8e6d0e3124378ca69ed5acd2578792", - "transaction":{ - "conditions":[ - { - "cid":0, - "condition":{ - "details":{ - "bitmask":32, - "public_key":"CwA8s2QYQBfNz4WvjEwmJi83zYr7JhxRhidx6uZ5KBVd", - "signature":null, - "type":"fulfillment", - "type_id":4 - }, - "uri":"cc:4:20:sVA_3p8gvl8yRFNTomqm6MaavKewka6dGYcFAuPrRXQ:96" - }, - "owners_after":[ - "CwA8s2QYQBfNz4WvjEwmJi83zYr7JhxRhidx6uZ5KBVd" - ] + "transaction": { + "conditions": [ + { + "cid": 0, + "condition": { + "uri": "cc:4:20:GG-pi3CeIlySZhQoJVBh9O23PzrOuhnYI7OHqIbHjkk:96", + "details": { + "signature": null, + "type": "fulfillment", + "type_id": 4, + "bitmask": 32, + "public_key": "2ePYHfV3yS3xTxF9EE3Xjo8zPwq2RmLPFAJGQqQKc3j6" } - ], - "data":{ - "payload":null, - "uuid":"a9999d69-6cde-4b80-819d-ed57f6abe257" - }, - "fulfillments":[ - { - "owners_before":[ - "JEAkEJqLbbgDRAtMm8YAjGp759Aq2qTn9eaEHUj2XePE" - ], - "fid":0, - "fulfillment":"cf:4:__Y_Um6H73iwPe6ejWXEw930SQhqVGjtAHTXilPp0P01vE_Cx6zs3GJVoO1jhPL18C94PIVkLTGMUB2aKC9qsbIb3w8ejpOf0_I3OCuTbPdkd6r2lKMeVftMyMxkeWoM", - "input":{ - "cid":0, - "txid":"598ce4e9a29837a1c6fc337ee4a41b61c20ad25d01646754c825b1116abd8761" - } - } - ], - "operation":"TRANSFER", - "timestamp":"1471423869", - "version":1 - } + }, + "amount": 1, + "owners_after": [ + "2ePYHfV3yS3xTxF9EE3Xjo8zPwq2RmLPFAJGQqQKc3j6" + ] + } + ], + "operation": "CREATE", + "asset": { + "divisible": false, + "updatable": false, + "data": null, + "id": "aebeab22-e672-4d3b-a187-bde5fda6533d", + "refillable": false + }, + "metadata": null, + "timestamp": "1477578978", + "fulfillments": [ + { + "fid": 0, + "input": null, + "fulfillment": "cf:4:GG-pi3CeIlySZhQoJVBh9O23PzrOuhnYI7OHqIbHjkn2VnQaEWvecO1x82Qr2Va_JjFywLKIOEV1Ob9Ofkeln2K89ny2mB-s7RLNvYAVzWNiQnp18_nQEUsvwACEXTYJ", + "owners_before": [ + "2ePYHfV3yS3xTxF9EE3Xjo8zPwq2RmLPFAJGQqQKc3j6" + ] + } + ] + }, + "id": "2d431073e1477f3073a4693ac7ff9be5634751de1b8abaa1f4e19548ef0b4b0e", + "version": 1 } - :statuscode 201: A new transaction was created. - :statuscode 400: The transaction was invalid and not created. - - **Disclaimer** - - ``CREATE`` transactions are treated differently from ``TRANSFER`` assets. - The reason is that a ``CREATE`` transaction needs to be signed by a federation node and not by the client. - - The following python snippet in a client can be used to generate ``CREATE`` transactions before they can be pushed to the API server: - - .. code-block:: python - - from bigchaindb import util - tx = util.create_and_sign_tx(my_privkey, my_pubkey, my_pubkey, None, 'CREATE') - - When POSTing ``tx`` to the API, the ``CREATE`` transaction will be signed by a federation node. - - A ``TRANSFER`` transaction, that takes an existing input transaction to change ownership can be generated in multiple ways: - - .. code-block:: python - - from bigchaindb import util, Bigchain - tx = util.create_and_sign_tx(my_privkey, my_pubkey, other_pubkey, input_tx, 'TRANSFER') - # or - b = Bigchain() - tx_unsigned = b.create_transaction(my_pubkey, other_pubkey, input_tx, 'TRANSFER') - tx = b.sign_transaction(tx_unsigned, my_privkey) - - More information on generating transactions can be found in the `Python server API examples `_ \ No newline at end of file + :statuscode 200: A transaction with that ID was found. + :statuscode 404: A transaction with that ID was not found. \ No newline at end of file From b9b2ccdf62114b91eea077f3dfeda796b6dbf65e Mon Sep 17 00:00:00 2001 From: troymc Date: Thu, 27 Oct 2016 19:01:33 +0200 Subject: [PATCH 10/13] Updated Transaction Concepts heading and link --- docs/server/source/topic-guides/models.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/server/source/topic-guides/models.md b/docs/server/source/topic-guides/models.md index 64e22d84..e0265285 100644 --- a/docs/server/source/topic-guides/models.md +++ b/docs/server/source/topic-guides/models.md @@ -1,6 +1,6 @@ # The Transaction, Block and Vote Models -This page about the data models was getting too big, so it was split into smaller pages. It will be deleted eventually, so update your links. Here's where you can find the new pages: +This page about transaction concepts and data models was getting too big, so it was split into smaller pages. It will be deleted eventually, so update your links. Here's where you can find the new pages: -* [Transaction concepts](https://docs.bigchaindb.com/en/latest/transactions.html) +* [Transaction Concepts](https://docs.bigchaindb.com/en/latest/transaction-concepts.html) * [Data Models (all of them)](https://docs.bigchaindb.com/en/latest/data-models/index.html) From 97dd4eae85dae0f6ed1a8a89dcec9aeffd29a0e6 Mon Sep 17 00:00:00 2001 From: troymc Date: Fri, 28 Oct 2016 10:39:26 +0200 Subject: [PATCH 11/13] Removed page python-server-api-examples.md --- .../python-server-api-examples.md | 1313 ----------------- 1 file changed, 1313 deletions(-) delete mode 100644 docs/server/source/drivers-clients/python-server-api-examples.md diff --git a/docs/server/source/drivers-clients/python-server-api-examples.md b/docs/server/source/drivers-clients/python-server-api-examples.md deleted file mode 100644 index 62231e0c..00000000 --- a/docs/server/source/drivers-clients/python-server-api-examples.md +++ /dev/null @@ -1,1313 +0,0 @@ -# The Python Server API by Example - -**Currently, the HTTP Client-Server API is very rudimentary, so you may want to use the Python Server API to develop prototype clients and applications, for now. Keep in mind that in the future, clients will only be able to use the HTTP Client-Server API (and possibly other Client-Server APIs) to communicate with BigchainDB nodes.** - -This section has examples of using the Python Server API to interact _directly_ with a BigchainDB node running BigchainDB Server. That is, in these examples, the Python code and BigchainDB Server run on the same machine. - -One can also interact with a BigchainDB node via other APIs, including the HTTP Client-Server API. - - -## Getting Started - -First, make sure you have RethinkDB and BigchainDB _installed and running_, i.e. you [installed them](../dev-and-test/setup-run-node.html) and you ran: -```text -$ rethinkdb -$ bigchaindb configure -$ bigchaindb start -``` - -Don't shut them down! In a new terminal, open a Python shell: -```text -$ python -``` - -Now we can import the `Bigchain` class and create an instance: -```python -from bigchaindb import Bigchain -b = Bigchain() -``` - -This instantiates an object `b` of class `Bigchain`. When instantiating a `Bigchain` object without arguments (as above), it reads the configurations stored in `$HOME/.bigchaindb`. - -In a federation of BigchainDB nodes, each node has its own `Bigchain` instance. - -The `Bigchain` class is the main API for all BigchainDB interactions, right now. It does things that BigchainDB nodes do, but it also does things that BigchainDB clients do. In the future, it will be refactored into different parts. The `Bigchain` class is documented [elsewhere (link)](../appendices/the-Bigchain-class.html). - - -## Create a Digital Asset - -At a high level, a "digital asset" is something which can be represented digitally and can be assigned to a user. In BigchainDB, users are identified by their public key, and the data payload in a digital asset is represented using a generic [Python dict](https://docs.python.org/3.4/tutorial/datastructures.html#dictionaries). - -In BigchainDB, only the federation nodes are allowed to create digital assets, by doing a special kind of transaction: a `CREATE` transaction. - -```python -from bigchaindb import crypto - -# Create a test user -testuser1_priv, testuser1_pub = crypto.generate_key_pair() - -# Define a digital asset data payload -digital_asset_payload = {'msg': 'Hello BigchainDB!'} - -# 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 -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, -# included in a block, and written to the bigchain -b.write_transaction(tx_signed) -``` - -## Read the Creation Transaction from the DB - -After a couple of seconds, we can check if the transactions was included in the bigchain: -```python -# Retrieve a transaction from the bigchain -tx_retrieved = b.get_transaction(tx_signed['id']) -tx_retrieved -``` - -```python -{ - "id":"933cd83a419d2735822a2154c84176a2f419cbd449a74b94e592ab807af23861", - "transaction":{ - "conditions":[ - { - "cid":0, - "condition":{ - "details":{ - "bitmask":32, - "public_key":"BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs", - "signature":None, - "type":"fulfillment", - "type_id":4 - }, - "uri":"cc:4:20:oqXTWvR3afHHX8OaOO84kZxS6nH4GEBXD4Vw8Mc5iBo:96" - }, - "owners_after":[ - "BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs" - ] - } - ], - "data":{ - "hash":"872fa6e6f46246cd44afdb2ee9cfae0e72885fb0910e2bcf9a5a2a4eadb417b8", - "payload":{ - "msg":"Hello BigchainDB!" - } - }, - "fulfillments":[ - { - "owners_before":[ - "3LQ5dTiddXymDhNzETB1rEkp4mA7fEV1Qeiu5ghHiJm9" - ], - "fid":0, - "fulfillment":"cf:4:Iq-BcczwraM2UpF-TDPdwK8fQ6IXkD_6uJaxBZd984yxCGX7Csx-S2FBVe8LVyW2sAtmjsOSV0oiw9-s_9qSJB0dDUl_x8YQk5yxNdQyNVWVM1mWSGQL68gMngdmFG8O", - "input":None - } - ], - "operation":"CREATE", - "timestamp":"1460981667.449279" - }, - "version":1 -} - -``` - -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`) 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 `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 its own (crypto)condition, each transaction input should also refer to the condition index `cid`. - -

- -

- - -```python -# Create a second testuser -testuser2_priv, testuser2_pub = crypto.generate_key_pair() - -# Retrieve the transaction with condition id -tx_retrieved_id = b.get_owned_ids(testuser1_pub).pop() -tx_retrieved_id -``` - -```python -{ - "cid":0, - "txid":"933cd83a419d2735822a2154c84176a2f419cbd449a74b94e592ab807af23861" -} -``` - -```python -# Create a transfer transaction -tx_transfer = b.create_transaction(testuser1_pub, testuser2_pub, tx_retrieved_id, 'TRANSFER') - -# Sign the transaction -tx_transfer_signed = b.sign_transaction(tx_transfer, testuser1_priv) - -# Write the transaction -b.write_transaction(tx_transfer_signed) - -# Check if the transaction is already in the bigchain -tx_transfer_retrieved = b.get_transaction(tx_transfer_signed['id']) -tx_transfer_retrieved -``` - -```python -{ - "id":"aa11365317cb89bfdae2375bae76d6b8232008f8672507080e3766ca06976dcd", - "transaction":{ - "conditions":[ - { - "cid":0, - "condition":{ - "details":{ - "bitmask":32, - "public_key":"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor", - "signature":None, - "type":"fulfillment", - "type_id":4 - }, - "uri":"cc:4:20:DIfyalZvV_9ukoO01mxmK3nxsfAWSKYYF33XDYkbY4E:96" - }, - "owners_after":[ - "qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor" - ] - } - ], - "data":None, - "fulfillments":[ - { - "owners_before":[ - "BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs" - ], - "fid":0, - "fulfillment":"cf:4:oqXTWvR3afHHX8OaOO84kZxS6nH4GEBXD4Vw8Mc5iBqzkVR6cFJhRvMGKa-Lc81sdYWVu0ZSMPGht-P7s6FZLkRXDqrwwInabLhjx14eABY34oHb6IyWcB-dyQnlVNEI", - "input":{ - "cid":0, - "txid":"933cd83a419d2735822a2154c84176a2f419cbd449a74b94e592ab807af23861" - } - } - ], - "operation":"TRANSFER", - "timestamp":"1460981677.472037" - }, - "version":1 -} -``` - -## Double Spends - -BigchainDB makes sure that a user can't transfer the same digital asset two or more times (i.e. it prevents double spends). - -If we try to create another transaction with the same input as before, the transaction will be marked invalid and the validation will throw a double spend exception: - -```python -# Create another transfer transaction with the same input -tx_transfer2 = b.create_transaction(testuser1_pub, testuser2_pub, tx_retrieved_id, 'TRANSFER') - -# Sign the transaction -tx_transfer_signed2 = b.sign_transaction(tx_transfer2, testuser1_priv) - -# Check if the transaction is valid -b.validate_transaction(tx_transfer_signed2) -``` - -```python -DoubleSpend: input `{'cid': 0, 'txid': '933cd83a419d2735822a2154c84176a2f419cbd449a74b94e592ab807af23861'}` was already spent -``` - -## Multiple Owners - -To create a new digital asset with _multiple_ owners, one can simply provide a list of `owners_after`: - -```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 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 -tx_multisig_retrieved = b.get_transaction(tx_multisig_signed['id']) -tx_multisig_retrieved -``` - -```python -{ - "id":"a9a6e5c74ea02b8885c83125f1b74a2ba8ca42236ec5e1c358aa1053ec721ccb", - "transaction":{ - "conditions":[ - { - "cid":0, - "condition":{ - "details":{ - "bitmask":41, - "subfulfillments":[ - { - "bitmask":32, - "public_key":"BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs", - "signature":None, - "type":"fulfillment", - "type_id":4, - "weight":1 - }, - { - "bitmask":32, - "public_key":"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor", - "signature":None, - "type":"fulfillment", - "type_id":4, - "weight":1 - } - ], - "threshold":2, - "type":"fulfillment", - "type_id":2 - }, - "uri":"cc:2:29:DpflJzUSlnTUBx8lD8QUolOA-M9nQnrGwvWSk7f3REc:206" - }, - "owners_after":[ - "BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs", - "qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor" - ] - } - ], - "data":None, - "fulfillments":[ - { - "owners_before":[ - "3LQ5dTiddXymDhNzETB1rEkp4mA7fEV1Qeiu5ghHiJm9" - ], - "fid":0, - "fulfillment":"cf:4:Iq-BcczwraM2UpF-TDPdwK8fQ6IXkD_6uJaxBZd984z5qdHRz9Jag68dkOyZS5_YoTR_0WpwiUnBGoNgwjwEuIn5JNm7Kksi0nUnHsWssyXISkmqRnHH-30HQhKjznIH", - "input":None - } - ], - "operation":"CREATE", - "timestamp":"1460981687.501433" - }, - "version":1 -} -``` - -The asset can be transfered as soon as each of the `owners_after` signs the transaction. - -To do so, simply provide a list of all private keys to the signing routine: - -```python -# Create a third testuser -testuser3_priv, testuser3_pub = crypto.generate_key_pair() - -# Retrieve the multisig transaction -tx_multisig_retrieved_id = b.get_owned_ids(testuser2_pub).pop() - -# Transfer the asset from the 2 owners to the third testuser -tx_multisig_transfer = b.create_transaction([testuser1_pub, testuser2_pub], testuser3_pub, tx_multisig_retrieved_id, 'TRANSFER') - -# Sign with both private keys -tx_multisig_transfer_signed = b.sign_transaction(tx_multisig_transfer, [testuser1_priv, testuser2_priv]) - -# Write the transaction -b.write_transaction(tx_multisig_transfer_signed) - -# Check if the transaction is already in the bigchain -tx_multisig_transfer_retrieved = b.get_transaction(tx_multisig_transfer_signed['id']) -tx_multisig_transfer_retrieved -``` - -```python -{ - "id":"e689e23f774e7c562eeb310c7c712b34fb6210bea5deb9175e48b68810029150", - "transaction":{ - "conditions":[ - { - "cid":0, - "condition":{ - "details":{ - "bitmask":32, - "public_key":"8YN9fALMj9CkeCcmTiM2kxwurpkMzHg9RkwSLJKMasvG", - "signature":None, - "type":"fulfillment", - "type_id":4 - }, - "uri":"cc:4:20:cAq6JQJXtwlxURqrksiyqLThB9zh08ZxSPLTDSaReYE:96" - }, - "owners_after":[ - "8YN9fALMj9CkeCcmTiM2kxwurpkMzHg9RkwSLJKMasvG" - ] - } - ], - "data":None, - "fulfillments":[ - { - "owners_before":[ - "BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs", - "qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor" - ], - "fid":0, - "fulfillment":"cf:4:oqXTWvR3afHHX8OaOO84kZxS6nH4GEBXD4Vw8Mc5iBrcuiGDNVgpH9SwiuNeYZ-nugSTbxykH8W1eH5UJiunmnBSlKnJb8_QYOQsMAXl3MyLq2pWAyI45ZSG1rr2CksI", - "input":{ - "cid":0, - "txid":"aa11365317cb89bfdae2375bae76d6b8232008f8672507080e3766ca06976dcd" - } - } - ], - "operation":"TRANSFER", - "timestamp":"1460981697.526878" - }, - "version":1 -} -``` - -## Multiple Inputs and Outputs - -With BigchainDB it is possible to send multiple assets to someone in a single transfer. - -The transaction will create a `fulfillment` - `condition` pair for each input, which can be refered to by `fid` and `cid` respectively. - -

- -

- -```python -# Create some assets for bulk transfer -for i in range(3): - tx_mimo_asset = b.create_transaction(b.me, testuser1_pub, None, 'CREATE') - tx_mimo_asset_signed = b.sign_transaction(tx_mimo_asset, b.me_private) - b.write_transaction(tx_mimo_asset_signed) - -# Wait until they appear on the bigchain and get the inputs -owned_mimo_inputs = b.get_owned_ids(testuser1_pub) - -# Check the number of assets -print(len(owned_mimo_inputs)) - -# 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) - -# Write the transaction -b.write_transaction(tx_mimo_signed) - -# Check if the transaction is already in the bigchain -tx_mimo_retrieved = b.get_transaction(tx_mimo_signed['id']) -tx_mimo_retrieved -``` - -```python -{ - "id":"8b63689691a3c2e8faba89c6efe3caa0661f862c14d88d1e63ebd65d49484de2", - "transaction":{ - "conditions":[ - { - "cid":0, - "condition":{ - "details":{ - "bitmask":32, - "public_key":"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor", - "signature":None, - "type":"fulfillment", - "type_id":4 - }, - "uri":"cc:4:20:2AXg2JJ7mQ8o2Q9-hafP-XmFh3YR7I2_Sz55AubfxIc:96" - }, - "owners_after":[ - "qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor" - ] - }, - { - "cid":1, - "condition":{ - "details":{ - "bitmask":32, - "public_key":"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor", - "signature":None, - "type":"fulfillment", - "type_id":4 - }, - "uri":"cc:4:20:2AXg2JJ7mQ8o2Q9-hafP-XmFh3YR7I2_Sz55AubfxIc:96" - }, - "owners_after":[ - "qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor" - ] - }, - { - "cid":2, - "condition":{ - "details":{ - "bitmask":32, - "public_key":"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor", - "signature":None, - "type":"fulfillment", - "type_id":4 - }, - "uri":"cc:4:20:2AXg2JJ7mQ8o2Q9-hafP-XmFh3YR7I2_Sz55AubfxIc:96" - }, - "owners_after":[ - "qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor" - ] - } - ], - "data":None, - "fulfillments":[ - { - "owners_before":[ - "BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs" - ], - "fid":0, - "fulfillment":"cf:4:sTzo4fvm8U8XrlXcgcGkNZgkfS9QHg2grgrJiX-c0LT_a83V0wbNRVbmb0eOy6tLyRw0kW1FtsN29yTcTAILX5-fyBITrPUqPzIzF85l8yIAMSjVfH-h6YNcUQBj0o4B", - "input":{ - "cid":0, - "txid":"9a99f3c82aea23fb344acb1505926365e2c6b722761c4be6ab8916702c94c024" - } - }, - { - "owners_before":[ - "BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs" - ], - "fid":1, - "fulfillment":"cf:4:sTzo4fvm8U8XrlXcgcGkNZgkfS9QHg2grgrJiX-c0LSJe3B_yjgXd1JHPBJhAdywCzR_ykEezi3bPNucGHl5mgPvpsLpHWrdIvZa3arFD91AepXILaNCF0y8cxIBOyEE", - "input":{ - "cid":0, - "txid":"783014b92f35da0c2526e1db6f81452c61853d29eda50d057fd043d507d03ef9" - } - }, - { - "owners_before":[ - "BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs" - ], - "fid":2, - "fulfillment":"cf:4:sTzo4fvm8U8XrlXcgcGkNZgkfS9QHg2grgrJiX-c0LReUQd-vDMseuVi03qY5Fxetv81fYpy3z1ncHIGc2bX7R69aS-yH5_deV9qaKjc1ZZFN5xXsB9WFpQkf9VQ-T8B", - "input":{ - "cid":0, - "txid":"9ab6151334b06f3f3aab282597ee8a7c12b9d7a0c43f356713f7ef9663375f50" - } - } - ], - "operation":"TRANSFER", - "timestamp":"1461049149.568927" - }, - "version":1 -} -``` - - -## Crypto-Conditions (Advanced) - -### Introduction - -Crypto-conditions provide a mechanism to describe a signed message such that multiple actors in a distributed system can all verify the same signed message and agree on whether it matches the description. - -This provides a useful primitive for event-based systems that are distributed on the Internet since we can describe events in a standard deterministic manner (represented by signed messages) and therefore define generic authenticated event handlers. - -Crypto-conditions are part of the Interledger protocol and the full specification can be found [here](https://interledger.org/five-bells-condition/spec.html). - -Implementations of the crypto-conditions are available in [Python](https://github.com/bigchaindb/cryptoconditions) and [JavaScript](https://github.com/interledger/five-bells-condition). - - -### Threshold Conditions - -Threshold conditions introduce multi-signatures, m-of-n signatures or even more complex binary Merkle trees to BigchainDB. - -Setting up a generic threshold condition is a bit more elaborate than regular transaction signing but allow for flexible signing between multiple parties or groups. - -The basic workflow for creating a more complex cryptocondition is the following: - -1. Create a transaction template that include the public key of all (nested) parties as `owners_after` -2. Set up the threshold condition using the [cryptocondition library](https://github.com/bigchaindb/cryptoconditions) -3. Update the condition and hash in the transaction template - -We'll illustrate this by a threshold condition where 2 out of 3 `owners_after` need to sign the transaction: - -```python -import copy - -import cryptoconditions as cc -from bigchaindb import util, crypto - -# Create some new testusers -thresholduser1_priv, thresholduser1_pub = crypto.generate_key_pair() -thresholduser2_priv, thresholduser2_pub = crypto.generate_key_pair() -thresholduser3_priv, thresholduser3_pub = crypto.generate_key_pair() - -# Retrieve the last transaction of testuser2 -tx_retrieved_id = b.get_owned_ids(testuser2_pub).pop() - -# Create a base template for a 1-input/2-output transaction -threshold_tx = b.create_transaction(testuser2_pub, [thresholduser1_pub, thresholduser2_pub, thresholduser3_pub], tx_retrieved_id, 'TRANSFER') - -# Create a Threshold Cryptocondition -threshold_condition = cc.ThresholdSha256Fulfillment(threshold=2) -threshold_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=thresholduser1_pub)) -threshold_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=thresholduser2_pub)) -threshold_condition.add_subfulfillment(cc.Ed25519Fulfillment(public_key=thresholduser3_pub)) - -# Update the condition in the newly created transaction -threshold_tx['transaction']['conditions'][0]['condition'] = { - 'details': threshold_condition.to_dict(), - 'uri': threshold_condition.condition.serialize_uri() -} - -# Conditions have been updated, so the transaction hash (ID) needs updating -threshold_tx['id'] = util.get_hash_data(threshold_tx) - -# Sign the transaction -threshold_tx_signed = b.sign_transaction(threshold_tx, testuser2_priv) - -# Write the transaction -b.write_transaction(threshold_tx_signed) - -# Check if the transaction is already in the bigchain -tx_threshold_retrieved = b.get_transaction(threshold_tx_signed['id']) -tx_threshold_retrieved -``` - -```python -{ - "id":"0057d29ff735d91505decf5e7195ea8da675b01676165abf23ea774bbb469383", - "transaction":{ - "conditions":[ - { - "cid":0, - "condition":{ - "details":{ - "bitmask":41, - "subfulfillments":[ - { - "bitmask":32, - "public_key":"8NaGq26YMcEvj8Sc5MnqspKzFTQd1eZBAuuPDw4ERHpz", - "signature":None, - "type":"fulfillment", - "type_id":4, - "weight":1 - }, - { - "bitmask":32, - "public_key":"ALE9Agojob28D1fHWCxFXJwpqrYPkcsUs26YksBVj27z", - "signature":None, - "type":"fulfillment", - "type_id":4, - "weight":1 - }, - { - "bitmask":32, - "public_key":"Cx4jWSGci7fw6z5QyeApCijbwnMpyuhp4C1kzuFc3XrM", - "signature":None, - "type":"fulfillment", - "type_id":4, - "weight":1 - } - ], - "threshold":2, - "type":"fulfillment", - "type_id":2 - }, - "uri":"cc:2:29:FoElId4TE5TU2loonT7sayXhxwcmaJVoCeIduh56Dxw:246" - }, - "owners_after":[ - "8NaGq26YMcEvj8Sc5MnqspKzFTQd1eZBAuuPDw4ERHpz", - "ALE9Agojob28D1fHWCxFXJwpqrYPkcsUs26YksBVj27z", - "Cx4jWSGci7fw6z5QyeApCijbwnMpyuhp4C1kzuFc3XrM" - ] - } - ], - "data":None, - "fulfillments":[ - { - "owners_before":[ - "qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor" - ], - "fid":0, - "fulfillment":"cf:4:DIfyalZvV_9ukoO01mxmK3nxsfAWSKYYF33XDYkbY4EbD7-_neXJJEe_tVTDc1_EqldlP_ulysFMprcW3VG4gzLzCMMpxA8kCr_pvywSFIEVYJHnI1csMvPivvBGHvkD", - "input":{ - "cid":0, - "txid":"aa11365317cb89bfdae2375bae76d6b8232008f8672507080e3766ca06976dcd" - } - } - ], - "operation":"TRANSFER", - "timestamp":"1460981707.559401" - }, - "version":1 -} -``` - -The transaction can now be transfered by fulfilling the threshold condition. - -The fulfillment involves: - -1. Create a transaction template that include the public key of all (nested) parties as `owners_before` -2. Parsing the threshold condition into a fulfillment using the [cryptocondition library](https://github.com/bigchaindb/cryptoconditions) -3. Signing all necessary subfulfillments and updating the fulfillment field in the transaction - - -```python -# Create a new testuser to receive -thresholduser4_priv, thresholduser4_pub = crypto.generate_key_pair() - -# Retrieve the last transaction of thresholduser1_pub -tx_retrieved_id = b.get_owned_ids(thresholduser1_pub).pop() - -# Create a base template for a 2-input/1-output transaction -threshold_tx_transfer = b.create_transaction([thresholduser1_pub, thresholduser2_pub, thresholduser3_pub], thresholduser4_pub, tx_retrieved_id, 'TRANSFER') - -# Parse the threshold cryptocondition -threshold_fulfillment = cc.Fulfillment.from_dict(threshold_tx['transaction']['conditions'][0]['condition']['details']) - -subfulfillment1 = threshold_fulfillment.get_subcondition_from_vk(thresholduser1_pub)[0] -subfulfillment2 = threshold_fulfillment.get_subcondition_from_vk(thresholduser2_pub)[0] -subfulfillment3 = threshold_fulfillment.get_subcondition_from_vk(thresholduser3_pub)[0] - - -# Get the fulfillment message to sign -threshold_tx_fulfillment_message = util.get_fulfillment_message(threshold_tx_transfer, - threshold_tx_transfer['transaction']['fulfillments'][0], - serialized=True) - -# Clear the subconditions of the threshold fulfillment, they will be added again after signing -threshold_fulfillment.subconditions = [] - -# Sign and add the subconditions until threshold of 2 is reached -subfulfillment1.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser1_priv)) -threshold_fulfillment.add_subfulfillment(subfulfillment1) -subfulfillment2.sign(threshold_tx_fulfillment_message, crypto.SigningKey(thresholduser2_priv)) -threshold_fulfillment.add_subfulfillment(subfulfillment2) - -# Add remaining (unfulfilled) fulfillment as a condition -threshold_fulfillment.add_subcondition(subfulfillment3.condition) - -# Update the fulfillment -threshold_tx_transfer['transaction']['fulfillments'][0]['fulfillment'] = threshold_fulfillment.serialize_uri() - -# Optional validation checks -assert threshold_fulfillment.validate(threshold_tx_fulfillment_message) == True -assert b.validate_fulfillments(threshold_tx_transfer) == True -assert b.validate_transaction(threshold_tx_transfer) - -b.write_transaction(threshold_tx_transfer) -threshold_tx_transfer -``` - -```python -{ - "id":"a45b2340c59df7422a5788b3c462dee708a18cdf09d1a10bd26be3f31af4b8d7", - "transaction":{ - "conditions":[ - { - "cid":0, - "condition":{ - "details":{ - "bitmask":32, - "public_key":"ED2pyPfsbNRTHkdMnaFkAwCSpZWRmbaM1h8fYzgRRMmc", - "signature":None, - "type":"fulfillment", - "type_id":4 - }, - "uri":"cc:4:20:xDz3NhRG-3eVzIB9sgnd99LKjOyDF-KlxWuf1TgNT0s:96" - }, - "owners_after":[ - "ED2pyPfsbNRTHkdMnaFkAwCSpZWRmbaM1h8fYzgRRMmc" - ] - } - ], - "data":None, - "fulfillments":[ - { - "owners_before":[ - "8NaGq26YMcEvj8Sc5MnqspKzFTQd1eZBAuuPDw4ERHpz", - "ALE9Agojob28D1fHWCxFXJwpqrYPkcsUs26YksBVj27z", - "Cx4jWSGci7fw6z5QyeApCijbwnMpyuhp4C1kzuFc3XrM" - ], - "fid":0, - "fulfillment":"cf:2:AQIBAwEBACcABAEgILGLuLLaNHo-KE59tkrpYmlVeucu16Eg9TcSuBqnMVwmAWABAWMABGBtiKCT8NBtSdnxJNdGYkyWqoRy2qOeNZ5UdUvpALcBD4vGRaohuVP9pQYNHpAA5GjTNNQT9CVMB67D8QL_DJsRU8ICSIVIG2P8pRqX6oia-304Xqq67wY-wLh_3IKlUg0AAQFjAARgiqYTeWkT6-jRMriCK4i8ceE2TwPys0JXgIrbw4kbwElVNnc7Aqw5c-Ts8-ymLp3d9_xTIb3-mPaV4JjhBqcobKuq2msJAjrxZOEeuYuAyC0tpduwTajOyp_Kmwzhdm8PAA", - "input":{ - "cid":0, - "txid":"0057d29ff735d91505decf5e7195ea8da675b01676165abf23ea774bbb469383" - } - } - ], - "operation":"TRANSFER", - "timestamp":"1460981717.579700" - }, - "version":1 -} -``` - - -### Hash-locked Conditions - -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. - -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 `owners_after`. Anyone who can fullfill the hash-lock condition can transfer the asset to themselves. - -```python -# Create a hash-locked asset without any owners_after -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, - 'owners_after': None -}) - -# 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 owner_before -hashlock_tx_signed = b.sign_transaction(hashlock_tx, b.me_private) - -# Some validations -assert b.validate_transaction(hashlock_tx_signed) == hashlock_tx_signed - -b.write_transaction(hashlock_tx_signed) -hashlock_tx_signed -``` - -```python -{ - "id":"604c520244b7ff63604527baf269e0cbfb887122f503703120fd347d6b99a237", - "transaction":{ - "conditions":[ - { - "cid":0, - "condition":{ - "uri":"cc:0:3:nsW2IiYgk9EUtsg4uBe3pBnOgRoAEX2IIsPgjqZz47U:17" - }, - "owners_after":None - } - ], - "data":None, - "fulfillments":[ - { - "owners_before":[ - "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 with the correct secret: - -```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 - -b.write_transaction(hashlock_fulfill_tx) -hashlock_fulfill_tx -``` - -```python -{ - "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" - }, - "owners_after":[ - "EiqCKxnBCmmNb83qyGch48tULK9RLaEt4xFA43UVCVDb" - ] - } - ], - "data":None, - "fulfillments":[ - { - "owners_before":[], - "fid":0, - "fulfillment":"cf:0:bXVjaCBzZWNyZXQhIHdvdyE", - "input":{ - "cid":0, - "txid":"604c520244b7ff63604527baf269e0cbfb887122f503703120fd347d6b99a237" - } - } - ], - "operation":"TRANSFER", - "timestamp":"1461250397.944510" - }, - "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](#escrow). - -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. - -__Caveat__: The times between nodes in a BigchainDB federation may (and will) differ slightly. In this case, the majority of the nodes will decide. - -```python -# Create a timeout asset without any owners_after -tx_timeout = 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': condition_timeout.to_dict(), - 'uri': condition_timeout.condition.serialize_uri() - }, - 'cid': 0, - 'owners_after': 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 owner_before -tx_timeout_signed = b.sign_transaction(tx_timeout, b.me_private) - -# Some validations -assert b.validate_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" - }, - "owners_after":null - } - ], - "data":null, - "fulfillments":[ - { - "owners_before":[ - "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 -from time import sleep - -# 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_dict( - 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 inverted timeout is denoted by a -1 threshold, which negates the output of the fulfillment. - -```python -inverted_fulfillment.validate(msg) == not fulfillment.validate(msg) -``` - -__Note__: inverted thresholds are BigchainDB-specific and not supported by the ILP standard. -The main reason is that it's difficult to tell whether the fulfillment was negated, or just omitted. - - -The following code snippet shows how to create an escrow condition: - -```python -# Retrieve the last transaction of testuser2_pub (or create a new asset) -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 -condition_timeout_inverted = cc.InvertedThresholdSha256Fulfillment(threshold=1) -condition_timeout_inverted.add_subfulfillment(condition_timeout) # invert the timeout condition - -# 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_inverted) -condition_escrow.add_subfulfillment(condition_abort) - -# Update the condition in the newly created transaction -tx_escrow['transaction']['conditions'][0]['condition'] = { - 'details': condition_escrow.to_dict(), - '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 owner_before -tx_escrow_signed = b.sign_transaction(tx_escrow, testuser2_priv) - -# Some validations -assert b.validate_transaction(tx_escrow_signed) == tx_escrow_signed - -b.write_transaction(tx_escrow_signed) -tx_escrow_signed -``` - -```python -{ - "id":"1a281da2b9bc3d2beba92479058d440de3353427fd64045a61737bad0d0c809c", - "transaction":{ - "conditions":[ - { - "cid":0, - "condition":{ - "details":{ - "bitmask":41, - "subfulfillments":[ - { - "bitmask":41, - "subfulfillments":[ - { - "bitmask":32, - "public_key":"qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor", - "signature":null, - "type":"fulfillment", - "type_id":4, - "weight":1 - }, - { - "bitmask":9, - "expire_time":"1464242352.227917", - "type":"fulfillment", - "type_id":99, - "weight":1 - } - ], - "threshold":2, - "type":"fulfillment", - "type_id":2, - "weight":1 - }, - { - "bitmask":41, - "subfulfillments":[ - { - "bitmask":32, - "public_key":"BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs", - "signature":null, - "type":"fulfillment", - "type_id":4, - "weight":1 - }, - { - "bitmask":9, - "subfulfillments":[ - { - "bitmask":9, - "expire_time":"1464242352.227917", - "type":"fulfillment", - "type_id":99, - "weight":1 - } - ], - "threshold":1, - "type":"fulfillment", - "type_id":98, - "weight":1 - } - ], - "threshold":2, - "type":"fulfillment", - "type_id":2, - "weight":1 - } - ], - "threshold":1, - "type":"fulfillment", - "type_id":2 - }, - "uri":"cc:2:29:sg08ERtppQrGxot7mu7XMdNkZTc29xCbWE1r8DgxuL8:181" - }, - "owners_after":[ - "BwuhqQX8FPsmqYiRV2CSZYWWsSWgSSQQFHjqxKEuqkPs", - "qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor" - ] - } - ], - "data":null, - "fulfillments":[ - { - "owners_before":[ - "qv8DvdNG5nZHWCP5aPSqgqxAvaPJpQj19abRvFCntor" - ], - "fid":0, - "fulfillment":"cf:4:B6VAa7KAMD1v-pyvDx9RuBLb6l2Qs3vhucgXqzU_RbuRucOp6tNY8AoNMoC-HAOZBJSnHXZsdJ7pLCZ6aDTwUHXf0zxyLaCgy1NpES3h8qcuxbfv4Nchw3BtUcVSY3AM", - "input":{ - "cid":1, - "txid":"d3f5e78f6d4346466178745f1c01cbcaf1c1dce1932a16cd653051b16ee29bac" - } - } - ], - "operation":"TRANSFER", - "timestamp":"1464242340.227787" - }, - "version":1 -} -``` - -At any given moment `testuser1` and `testuser2` can try to fulfill the `execute` and `abort` branch respectively. -Whether the fulfillment will validate depends on the timeout condition. - -We'll illustrate this by example. - -In the case of `testuser1`, we create the `execute` fulfillment: - -```python -# Create a base template for execute fulfillment -tx_escrow_execute = b.create_transaction([testuser2_pub, testuser1_pub], testuser1_pub, {'txid': tx_escrow_signed['id'], 'cid': 0}, 'TRANSFER') - -# Parse the Escrow cryptocondition -escrow_fulfillment = cc.Fulfillment.from_dict( - 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'] -subfulfillment_timeout_inverted = escrow_fulfillment.subconditions[1]['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) - -# Clear the subconditions of the escrow fulfillment -escrow_fulfillment.subconditions = [] - -# Fulfill the 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 the abort branch -condition_abort = cc.ThresholdSha256Fulfillment(threshold=2) -condition_abort.add_subfulfillment(subfulfillment_testuser2) -condition_abort.add_subfulfillment(subfulfillment_timeout_inverted) -escrow_fulfillment.add_subcondition(condition_abort.condition) # Adding only the condition here - -# Update the execute transaction with the fulfillment -tx_escrow_execute['transaction']['fulfillments'][0]['fulfillment'] = escrow_fulfillment.serialize_uri() -``` - -In the case of `testuser2`, we create the `abort` fulfillment: - -```python -# Create a base template for execute fulfillment -tx_escrow_abort = b.create_transaction([testuser2_pub, testuser1_pub], testuser2_pub, {'txid': tx_escrow_signed['id'], 'cid': 0}, 'TRANSFER') - -# Parse the threshold cryptocondition -escrow_fulfillment = cc.Fulfillment.from_dict( - 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'] -subfulfillment_timeout_inverted = escrow_fulfillment.subconditions[1]['body'].subconditions[1]['body'] - -# Get the fulfillment message to sign -tx_escrow_abort_fulfillment_message = \ - util.get_fulfillment_message(tx_escrow_abort, - tx_escrow_abort['transaction']['fulfillments'][0], - serialized=True) - -# Clear the subconditions of the escrow fulfillment -escrow_fulfillment.subconditions = [] - -# Do not fulfill the 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) # Adding only the condition here - -# Fulfill the 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_inverted) -escrow_fulfillment.add_subfulfillment(fulfillment_abort) - -# Update the abort transaction with the fulfillment -tx_escrow_abort['transaction']['fulfillments'][0]['fulfillment'] = escrow_fulfillment.serialize_uri() -``` - -The following demonstrates that the transaction validation switches once the timeout occurs: - -```python -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 - - seconds_to_timeout = int(float(time_expire) - float(util.timestamp())) - print('tx_execute valid: {} - tx_abort valid {} ({}s to timeout)'.format(valid_execute, valid_abort, seconds_to_timeout)) - sleep(1) -``` - -If you execute in a timely fashion, you should see the following: - -```python -tx_execute valid: True - tx_abort valid False (3s to timeout) -tx_execute valid: True - tx_abort valid False (2s to timeout) -tx_execute valid: True - tx_abort valid False (1s to timeout) -tx_execute valid: True - tx_abort valid False (0s to timeout) -tx_execute valid: False - tx_abort valid True (0s to timeout) -tx_execute valid: False - tx_abort valid True (-1s to timeout) -tx_execute valid: False - tx_abort valid True (-2s to timeout) -tx_execute valid: False - tx_abort valid True (-3s to timeout) -``` - -Of course, when the `execute` transaction was accepted in-time by bigchaindb, then writing the `abort` transaction after expiry will yield a `Doublespend` error. From 0fb9c7539ac47781512f8c63972e404a3e9fd628 Mon Sep 17 00:00:00 2001 From: troymc Date: Fri, 28 Oct 2016 10:40:44 +0200 Subject: [PATCH 12/13] Removed python-server-api-examples from index --- docs/server/source/drivers-clients/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/server/source/drivers-clients/index.rst b/docs/server/source/drivers-clients/index.rst index 428861c8..1c55d133 100644 --- a/docs/server/source/drivers-clients/index.rst +++ b/docs/server/source/drivers-clients/index.rst @@ -4,7 +4,6 @@ Drivers & Clients .. toctree:: :maxdepth: 1 - python-server-api-examples http-client-server-api python-driver example-apps From b55dd4ae290e63ad77d59beb510ad8fdc821c1f3 Mon Sep 17 00:00:00 2001 From: troymc Date: Fri, 28 Oct 2016 10:51:58 +0200 Subject: [PATCH 13/13] Updated the end of quickstart.md to point reader to the Python driver docs --- docs/server/source/quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/server/source/quickstart.md b/docs/server/source/quickstart.md index 2b2e0bb1..89a20ceb 100644 --- a/docs/server/source/quickstart.md +++ b/docs/server/source/quickstart.md @@ -34,4 +34,4 @@ bigchaindb start That's it! -For now, you can get a good sense of how to work with BigchainDB Server by going through [the examples in the section on the Python Server API](drivers-clients/python-server-api-examples.html). +Next Steps: You could build valid transactions and push them to your running BigchainDB Server using the [BigchaindB Python Driver](https://docs.bigchaindb.com/projects/py-driver/en/latest/index.html).