DAO technical overview

From Bisq Wiki
Revision as of 15:20, 28 September 2020 by Bayer (talk | contribs) (→‎Lockup tx)
Jump to navigation Jump to search

WORK IN PROGRESS

This document is a detailed technical overview of the Bisq DAO and BSQ token. Although outdated, please see Phase Zero: A plan for bootstrapping the Bisq DAO,for a high-level overview and rationale,

BSQ token

BSQ is a colored coin based on Bitcoin. One BSQ is represented by 100 bitcoin satoshis.

The colored coin concept does not require OpReturn data but uses the transaction graph to determine if a tx output originates in either the genesis tx or an issuance transaction.

BSQ inherits all the transaction rules from Bitcoin and adds some additional rules. Even though BSQ transactions do not require OP_RETURN, it will be used for certain specialized transactions (voting, compensation requests, etc). Aside from the ancestry to the genesis or an issuance transaction, there is another important rule: the outputs are parsed in a way that the first outputs are interpreted as BSQ as long there is sufficient BSQ value available from the inputs. So the order of BSQ and BTC outputs is essential! For inputs the order is irrelevant. Any violation of those rules would make BSQ invalid. There are many more details which are not currently covered in this document.

We use the Bisq P2P network as a carrier for content-rich data like that of proposals or voting. The blockchain is used for timestamping that data. Both the P2P network data and the tx are linked together and are used for creating network consensus.

BSQ is a result of blockchain-related data and P2P network data.

Infrastructure

The Bisq DAO is based on Bitcoin blockchain data as well as on data from the Bisq P2P network. Each Bisq application verifies the rules of the DAO. The degree of trust to data delivered from other nodes can be determined by the user. Running a full DAO node requires running bitcoind with RPC enabled. The DAO state can be rebuilt from the genesis transaction. The only remaining trusted entity are then the seed nodes which deliver past P2P network data. As seed node operators are bonded, risk for abuse is very limited. There are (at the moment) 8 seed nodes and all need to be in consensus on P2P network data. The user can see the consensus in the application (Network Monitor tab).

Nodes

A user can decide to run the application as lite node or full node. By default it runs as lite node as that does not require any additional setup.

Full nodes

A fully-validating BSQ node has the requirement to run a Bitcoin Core (bitcoind) node to provide the blockchain data for verification. The communication is done via RPC. The details about the setup can be found in the documentation folder of the source code repository.

Full nodes receive a notification from Bitcoin Core at each new block, scan the block for BSQ transactions and broadcast those to the Bisq P2P network. Every transaction with any BSQ input or output (issuance) is considered a BSQ transaction. The full node also listens to network messages from lite nodes which request BSQ blocks from a certain block height. The full node sends back the list of all blocks since the requested height. The bandwidth requirements for this will depend on the number of BSQ transactions, but rough estimations suggest that there will be no considerable issues. Bisq seed nodes are used as full nodes since those are the first nodes to which a user gets connected and we can use the existing connection to transmit the additional data early in the startup process.

Lite nodes

Most users will likely operate in lite node mode. They have to trust the seed node operators that they are not all colluding and holding data back. If at least one operator is honest the lite node can detect a conflict and would re-validate each block from the last snapshot or even from the genesis block. The UI will notify the user about conflicting data from seed nodes.

At startup, a lite node requests the missing BSQ blocks from the seed node and then validates those blocks to achieve a local state of valid and unspent BSQ outputs. In case of chain splits it can be that one of the seed nodes is on another chain and conflicting blocks get propagated. This would trigger a re-validation of all blocks from the latest snapshot for the lite node. The last received block would be considered the current state but the user will see a message saying there are conflicts (and that it is recommended to wait for more than one confirmation before considering a BSQ transaction as valid). Only after all full nodes (seed nodes) have the same state again will the lite node exit the "warning" state. If the user waits for a sufficiently high number of confirmations (4-6) he will not risk that his validation was based on an orphaned chain and that he could become victim of a double spend.

Seed nodes

Seed nodes act as providers for P2P network data and filtered blocks from the Bitcoin blockchain for lite nodes. When a node starts, it requests all P2P network data from several seed nodes.

External DAO monitor

Monitoring of DAO-related data and infrastructure will be added to the Bisq monitoring. This should help us spot any potential consensus or network conflict early.

This is not deployed at the moment, but will be integrated soon.

BSQ block explorer

The BSQ block explorer shows all BSQ transactions with some metadata (transaction type, etc). It gives also some statistical data about the network. It is a very basic version at the moment, but we are working on a more sophisticated version. Any BSQ transaction can be looked up in a normal Bitcoin block explorer as well, but of course those explorers will not show any DAO-related context. If looking up a BSQ address on a normal Bitcoin block explorer, a user needs to remove the B prefix so the address is considered a valid BTC address.

BSQ integration on bisq

The Bisq DAO and BSQ are fully integrated into the Bisq UI. It comes with a BSQ wallet and UI for creating proposals, participating in voting, and taking part in other DAO functions.

Wallet

The Bisq application provides an integrated BSQ wallet with basic features for receiving and sending BSQ, as well as a transaction history screen. The wallet is based on BIP 44and uses registered coin type 142. This provides extra protection against the risk of accidentally using the BSQ wallet as a BTC wallet (e.g., when restoring from seed words). To avoid users from needing to backup 2 different sets of seed words, we use the same seed for both the BSQ and the BTC wallets, even though they are stored in different files. To further avoid mixing BSQ with normal Bitcoin, we use a "B" as address prefix for BSQ addresses in the user interface. Internally that prefix does not exist, as a BSQ address is a normal BTC address, and BSQ transactions are normal BTC transactions.

BSQ token transactions and balances are represented inside the application but there is also a web-based BSQ block explorer.

A BSQ transaction is valid only after a blockchain confirmation. However, for better usability, we allow users to spend their own change outputs. This involves no risk, as a user would render all follow-up transactions invalid if he tries to double-spend. Unconfirmed BSQ received from others is not spendable.

Application internal DAO monitor

Inside the application we maintain a hash chain of states and P2P network data. The overall DAO state gets hashed at each new block which contains the previous hash, thus forming a chain of hashes. If the last hash is correct, all the previous must be correct as well. Each node receives the last 10 hashes from seed nodes and compares it with its local hash. If there is any conflict, it shows a warning and requests to rebuild the DAO state. At each new block, each peer broadcasts its local hash to its neighbors. That way, the node also receives hashes from normal peers.

Similar to DAO states, we also maintain a hash chain for proposal data and blind vote data. These hashes are created only once per voting cycle at an appropriate block height (i.e., when it is expected that the whole network has received all data).

There are valid cases when consensus could be temporarily broken. In case of a chain split, nodes can have different DAO states, as the Bitcoin block hash is part of the data, and if 2 nodes are on a different chain they will have different block hashes.

In case some P2P network data was not distributed well in the network, there may be temporary conflicts of the relevant hash chains. An application restart should usually resolve such issues. If not, rebuilding the DAO state forces all P2P network data to be reloaded.

Snapshots

To avoid reevaluating all history at each startup, we use a snapshot mechanism.

Every 20 blocks a snapshot mechanism is triggered. The current state is cloned and kept in memory, and if a previous clone exists, it is persisted. At the next snapshot trigger event, the last clone is persisted and a new clone is cached. In this way, the snapshot is always at least 20 blocks old.

The lite node requests the blocks since the latest snapshot only, so that will usually be 20-40 blocks (maximum). The only exception to this is on first startup after a new install, when a lite node only has the snapshot shipped with the binary—in this case, requested blocks might consume a bit more bandwidth.

If we maintain a monthly release schedule, there can be about 4500 blocks in a month, but even with that we expect not more than 1-5 MB of bandwidth to receive the initial blockchain data.

Snapshots shipped in releases

Each application release is updated with a recent snapshot version of the DAO state. This data will be used for new users who have not created their own snapshot yet. This saves new users from needing to download all historical data and rebuilding DAO state from genesis.

The user still can rebuild from genesis if he does not want to trust that developers have shipped a correct snapshot. Any discrepancy would be easily detected.

Blockchain related data

One part of the DAO is based on Bitcoin blockchain data. We only use the blockchain for timestamping. Transactions do not carry content-rich data—this data is stored on the Bisq P2P network.

List of possible BSQ transaction types:

  • Genesis tx
  • Transfer BSQ tx
  • Trade fee tx
  • Proposal tx
  • Compensation request tx
  • Reimbursement request tx
  • Blind vote tx
  • Vote reveal tx
  • Lockup tx
  • Unlock tx
  • Asset listing fee tx
  • Proof of burn tx

In addition, a transaction can be unverified, invalid or irregular.

Unverified is the default state for all unconfirmed BSQ transactions. Validation is done once a tx is confirmed.

Invalid transactions are transactions which have violated validation rules. BSQ are destroyed in such transactions.

Irregular transactions are transactions which are invalid with their intended use but have not destroyed their BSQ. An example is a proposal tx which got confirmed too late (not in proposal phase) and therefore is invalid as a proposal tx, but the BSQ is still valid to be spent.

Genesis tx

We use BTC from our donation address to fund the input for the genesis tx. We will issue 3 657 480 BSQ which is equivalent to 3.65748 BTC. The amount of 3 657 480 BSQ is the sum of the 2 500 000 BSQ which we distributed as symbolic testnet BSQ to past contributors back in July 2017 and 1 157 480 BSQ contributors have earned since we started the DAO Phase Zero in October 2017.

The outputs are the BSQ addresses of all contributors who have contributed to Bisq before we start the DAO on mainnet. All outputs are by definition valid BSQ. The genesis tx is funded with the exact amount, including the miner fee, so there is no change output.

Transfer BSQ tx

Sending BSQ to another address is a simple transaction without OpReturn. It requires a BSQ input for the transferred BSQ as well as a BTC input to cover the miner fee. The outputs are the receiver’s BSQ address, an optional BSQ change output, and an optional BTC change output.

A transaction to send 10 BSQ could look like this:

  • Input 1: 30.00 BSQ (BSQ sender)
  • Input 2: 0.01 BTC (required BTC for mining fee)
  • Output 1: 10.00 BSQ (BSQ receiver)
  • Output 1: 20.00 BSQ (BSQ change output back to sender)
  • Output 2: 0.0095 BTC (BTC change output)
  • Mining fee: 0.0005

In this case, we only used 9.50 BSQ of the 10.00 BSQ from the input. Since the second output is spending more than the remaining 0.50 BSQ, it is an invalid BSQ output so we consider it a BTC output. The remaining 0.50 BSQ which was not used in the first output will be used for the mining fee, thus reducing the mining fee which is paid from the BTC input (input 2).

Trade fee tx

We invalidate a small amount of BSQ for the trade fee payment. Since the burned amount is used as miner fee and not as a regular tx output, we are not restricted by the dust limit of 546 satoshis, and can spend fees as little as 0.01 BSQ (equivalent to 1 BTC satoshi). The fee is the difference of the BSQ input and the BSQ output.

  • A BSQ trade fee payment tx could look like this (for a fee with 0.5 BSQ):
  • Input 1: 10.00 BSQ
  • Input 2: 0.1 BTC
  • Output 1: 9.50 BSQ
  • Output 2: 0.09950050 BTC change output
  • Mining fee: 0.0005 (0.00049950 BTC + 0.00000050 BTC or 0.50 BSQ)

In this case, we only used 9.50 BSQ of the 10.00 BSQ from the input. Since the second output is spending more than the remaining 0.50 BSQ, it is an invalid BSQ output so we consider it a BTC output. The remaining 0.50 BSQ which was not used in the first output will be used for the mining fee, thus reducing the mining fee which is paid from the BTC input (input 2).

Proposal tx

A proposal transaction contains an OpReturn output which indicates the type and carries the hash of the proposal payload data.

  • Inputs [1-n]: BSQ inputs for BSQ fee
  • Inputs [1-n]: BTC inputs for miner fee
  • Output [1]: Mandatory BSQ output (BSQ input - fee)
  • Outputs [0-1]: BTC change output
  • Output [1]: OP_RETURN with OpReturnData and amount 0
  • Mining fee: BTC mining fee + burned BSQ fee

OpReturn data:

  • 1 byte for tx type: 0x10
  • 1 byte for version: 0x01
  • 20 bytes for hash of proposal payload

The hash is created from the bytes of the proposal payload with tx ID set to null using protobuffer serialization. It is first hashed with Sha256 and then with Ripemd160 to get a 20 byte hash.

Example with a BSQ fee of 2 BSQ:

  • Input 1: 10.00 BSQ
  • Input 2: 0.1 BTC
  • Output 1: 8 BSQ
  • Output 2: 0.09950200 BTC change output
  • Output 3: OpReturn data
  • Mining fee: 0.0005 (0.00049800 BTC + 0.00000200 BTC or 2 BSQ)

Compensation request tx/Reimbursement request tx

Compensation request tx and reimbursement request txs are technically the same and inherit the properties of a proposal tx but have some additional requirements. They add a BTC output which will be interpreted as a BSQ output at the vote result phase in case the request is accepted by voting.

  • Inputs [1-n]: BSQ inputs for BSQ fee
  • Inputs [1-n]: BTC inputs BSQ issuance and miner fee
  • Output [1]: Mandatory BSQ output (BSQ input - fee)
  • Outputs [1]: Issuance candidate output; before voted ok it is BTC afterwards newly issued BSQ
  • Outputs [0-1]: BTC change output
  • Outputs [1]: OP_RETURN with OpReturnData and amount 0
  • Mining fee: BTC mining fee + burned BSQ fee

OpReturn data:

  • 1 byte for tx type: Compensation request tx: 0x11 / Reimbursement request: 0x12
  • 1 byte for version: 0x01
  • 20 bytes for hash of request payload

Example with a BSQ fee of 2 BSQ and requested issuance amount of 5000 BSQ:

  • Input 1: 10.00 BSQ
  • Input 2: 0.1 BTC
  • Output 1: 8 BSQ
  • Output 2: 0.00500000 BTC (5000 BSQ after positive voting)
  • Output 3: 0.09950200 BTC change output
  • Output 4: OpReturn data
  • Mining fee: 0.0005 (0.00049800 BTC + 0.00000200 BTC or 2 BSQ)

Blind vote tx

The blind vote tx contains the hash of the blind vote payload and uses the vote stake as input. The stake is blocked from spending during this phase and is only unlocked by the vote reveal tx. If another transaction spends the stake, the blind vote becomes invalid. The blind vote requires a fee in BSQ.

  • Inputs [1-n]: BSQ inputs for BSQ fee + stake
  • Inputs [1-n]: BTC inputs for miner fee
  • Output [1]: Mandatory BSQ output of stake
  • Output [0-1] Optional BSQ change output
  • Outputs [0-1]: BTC change output
  • Output [1]: OP_RETURN with OpReturnData and amount 0
  • Mining fee: BTC mining fee + burned BSQ fee

OpReturn data:

  • 1 byte for tx type: 0x13
  • 1 byte for version: 0x01
  • 0 bytes for hash of encrypted votes

To create the encrypted votes we use following data:-

  • Secret key: 128 bit AES key.
  • List of a tuple of proposal Tx IDs + vote, sorted by tx ID. Only valid proposals of current cycle are included.

We use protobuffer serialisation for the bytes which will be encrypted with the secret key.

Example with a BSQ fee of 2 BSQ and 7000 BSQ vote stake:

  • Input 1: 8000.00 BSQ
  • Input 2: 0.1 BTC
  • Output 1: 7000 BSQ / 0.00700000 BTC
  • Output 2: 998 BSQ change output
  • Output 3: 0.09950200 BTC change output
  • Output 4: OpReturn data
  • Mining fee: 0.0005 (0.00049800 BTC + 0.00000200 BTC or 2 BSQ)

Vote reveal tx

The vote reveal tx consumes the stake output from the blind vote tx as the only BSQ input. It does not require a BSQ fee.

In the OpReturn data we add the secret key for decrypting our blind vote and a hash of the blind vote list to ensure consensus of the P2P network data used in voting. This hash will be used in the vote result phase to determine a majority in case different users get a different list of blind votes, which would lead to different vote results, and therefore cause consensus failures.

  • Input [1]: BSQ input → stake output of blind vote tx
  • Inputs [1-n]: BTC inputs for miner fee
  • Output [1]: BSQ output (unlocked stake)
  • Outputs [0-1]: BTC change output
  • Output [1]: OP_RETURN with OpReturnData and amount 0
  • Mining fee: BTC mining fee

OpReturn data:

  • 1 byte for tx type: 0x14
  • 1 byte for version: 0x01
  • 20 bytes for hash of blind vote list
  • 16 bytes secretKey

The hash of the blind vote list is made using all blind vote payload data received in the cycle and sorted by blind vote tx ID. The secretKey is the encoded byte representation of the secret key.

Example with 7000 BSQ stake:

  • Input 1: 7000 BSQ
  • Input 2: 0.1 BTC
  • Output 1: 7000 BSQ
  • Output 2: 0.09950000 BTC
  • Output 2: 0.09950000 BTC
  • Mining fee: 0.0005 BTC

Lockup tx

The lock tx can be use for locking up funds for a bonded role or for bonded reputation: a certain amount of BSQ is locked for a defined lock time (in blocks). Only an unlock tx can unlock locked funds. Once the unlock tx is confirmed, the lock time will be used to determine when the funds can be used in a normal transaction again. While funds are locked, they cannot be moved, or they are invalidated. While funds are locked, or are in an unlocking state, funds can be confiscated by voting.

  • Inputs [1-n]: BSQ inputs
  • Inputs [1-n]: BTC inputs for miner fee
  • Output [1]: Locked up BSQ
  • Outputs [0-1]: BSQ change output
  • Outputs [0-1]: BTC change output
  • Output [1]: OP_RETURN with OpReturnData and amount 0
  • Mining fee: BTC mining fee

OpReturn data:

  • 1 byte for tx type: 0x15
  • 1 byte for version: 0x01
  • 1 byte for lockup reason (bonded role 0x01, reputation 0x02)
  • 2 bytes for lock time (see: bisq.common.util.Utilities.integerToByteArray for encoding)
  • 20 bytes for hash

The hash in case of a bonded role is created from immutable data of the bonded role. Currently we use hashCode but that should be changed to a cryptographic hash. The hash for a reputation is derived from a salt. The salt is by default a random string as hex or can be any string defined by the user.

Example with locking up 4000 BSQ:

  • Input 1: 6000 BSQ
  • Input 2: 0.1 BTC
  • Output 1: 4000 BSQ lockup
  • Output 1: 2000 BSQ change output
  • Output 2: 0.09950000 BTC
  • Output 3: OpReturn data
  • Mining fee: 0.0005 BTC

Asset listing fee tx

Example with a BSQ fee of 20 BSQ:

Proof of burn tx

Example with 20 BSQ burned:

P2P network paylod

Proposals and blind vote data are published over the Bisq P2P network. They must be published in the correct phase and cycle, otherwise they are considered invalid. Each node listens for these messages and persists the data locally. At startup, each node receives missing data from seed nodes. The corresponding tx ID is part of the data and is used to map the data to the transaction. The hash of the P2P network data is part of the OpReturn data in the transactions. In this way, we can verify that the mapping of a tx to the data is correct in both directions.

Temporary proposal payload

During the proposal phase the user can add and remove proposals. For removing we use the public key which was added when publishing a proposal and verify with a signature if the remove attempt is coming from the same owner. This is the same model as we use in other P2P network data like offer payloads. The data has a time to live of 60 days, and after that, it is removed from local storage.

Proposal payload

There are several different types of proposals:

  • Compensation request
  • Reimbursement requests
  • Proposal for changing a parameter
  • Proposal for a bonded role
  • Proposal for confiscating a bond
  • Generic proposal
  • Proposal for removing an asset

The proposal contains the tx ID of the proposal transaction. When creating the transaction we add the 20-byte hash of the proposal data to the OpReturn data of the proposal tx. As the tx ID would be part of the proposal data and cannot be known before the tx is created, we leave it empty and set it afterwards. That way we get a mapping in both directions and can verify later that a proposal payload has a valid tx and that the tx data matches the proposal data.

During the break after the proposal phase, all nodes publish their proposal payload, which uses proposals from the temporary proposal payload. This data is now immutable and will be used for voting.

Blind vote payload

Blind vote data are published when the user makes his blind vote tx and are managed in the same way as proposal payloads (append-only data).

Governance

Disclaimer

Warn
This document does not cover all details and cannot be used as basis for implementation of BSQ features or for creating self-crafted transactions. The source code is the only real specification. It is NOT recommended to create custom BSQ transactions, as tiny mistakes can lead to destroyed BSQ. Bisq developers will not be concerned with transactions which might be valid with the current rule set but which have not been created by the Bisq application. In the future, updated rules might become more strict and might break such externally-created transactions. Requirements for backward compatibility will only consider use cases and tx structures created by the Bisq application.

Please note that currently it is not recommended to send BSQ to a hardware wallet. Handling the miner fee might cause invalidation of the BSQ funds or cause losses if precious BSQ is used to pay the miner fee. We will publish some instructions on how to do this in a safe way soon.