bitshares / bsips

BitShares Improvement Proposals and Protocols. These technical documents describe the process of updating and improving the BitShares blockchain and technical ecosystem.
https://bitshares.github.io
63 stars 86 forks source link

BSIP60: BitShares URI scheme #131

Closed jhtitor closed 5 years ago

jhtitor commented 5 years ago
BSIP: BSIP60
Title: BitShares URI Scheme
Authors: John Titor, Stefan Schießl, Abit More
Status: Draft
Type: Protocol
Created: 2019-02-11
Discussion: https://github.com/bitshares/bsips/issues/131

Abstract

A Uniform Resource Identifier (URI) is a string of characters that unambiguously identifies a particular resource.

The most common form of URI is the Uniform Resource Locator (URL), frequently referred to informally as a web address.

This BSIP defines a Uniform Resource Name (URN), for the BitShares network.

Motivation

Currently, BitShares lack any URL/URI scheme, forcing users to laborously copy and paste several pieces of data from/to different bitshares software.

Bitcoin (and other cryptocurrencies) generally have an URI scheme, making it possible to embed payment links into websites, emails and other forms of digital media.

Having a schema also enables support to generate and read QR codes. QR codes are of great convenience to the users, and is a defacto method of transfering URLs between desktop and mobile applications.

Even a mere existance of this BSIP could greatly raise interoperability between different BitShares software implementations.

Some clients have gone ahead and implemented their own incompatible schemas, which were never agreed on. This is not healthy for the ecosystem.

Rationale

The URI schema outlined in this BSIP is aimed to provide flexibility and future extensibility, while adhering to general Internet standarts.

The most requested form of an URI (representing a potential transfer) is defined here, along with a more generic, all-base-covering approach.

Specifications

The BitShares URI conforms to general URI structure, outlined in RFC1738.

url = protocol ":" path [ "?" params ]

Each URI points to an "noun", an object of some kind, and does not represent action (or "verb"). However, since BitShares Operation is an object, this scheme can express operations.

Protocol

The protocol name is bitshares.

protocol = "bitshares"

Paths

path = object_path | asset_path | account_path |
       operation_path | block_path | transaction_path |
       blind_receipt_path | public_key_path | market_path

All paths follow the path_type/path_ref structure.

path_type is always a string, and could be one of the object, asset, account, operation, market, blind_receipt, public_key, block or transaction. Future additional types are allowed.

path_refs differ by path type. For example, a graphene object is referenced by X.Y.Z 3-integer id, while a blind commitment might be referenced by it's 33-byte hash.

Note, that as BitShares blockchain evolves, some of the addressing schemes might get expanded, in which case the bitshares-core consensus always supersedes the rules specified in this BSIP.

Params

Parameters are URL-encoded. Parameters are key/value pairs separated by "=" symbol, delimited by "&".

?key1=value1&key2=value2

Extended syntax for nesting deep objects is also allowed, so those are valid:

?obj1[key1]=value1&obj1[key2]=value2 ?array[]=value1&array[]=value2

See Operation path definition for examples and rationale.

Raw Objects

Raw Object paths start with "object", followed by a graphene_id, which is 3 integers separated by a dot symbol, e.g. "1.2.0", as seen on BitShares blockchain.

Example: object/1.2.0

object_path    = "object" "/" graphene_id
graphene_id    = digit *[digit] "." digit *[digit] "." digit *[digit]
digit          = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
                 "8" | "9"

Assets

Asset paths start with the string "asset", followed by an asset_id_or_symbol, which could be a asset_id of the object, or it's "symbol" property.

Example: asset/BTS

asset_path           = "asset" "/" asset_id_or_symbol
asset_id_or_symbol   = asset_id | asset_symbol
asset_id             = "1.3." digit *[digit]
asset_symbol         = asset_symbol_segment [ "." | asset_symbol_segment ]
asset_symbol_segment = hialpha *[ hialpha | digit ] [ hialpha | digit ]
hialpha              = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
                       "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
                       "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"

Accounts

Account paths start with the string "account", followed by an account_id_or_name, which could be a graphene_id of the object, or it's "name" property.

Example: account/dan

account_path         = "account" "/" account_id_or_name
account_id_or_name   = account_id | account_name
account_id           = "1.2." digit *[digit]
account_name         = account_name_segment *[ "." account_name_segment ]
account_name_segment = lowalpha *[ lowalpha | digit | "-" ] [ lowalpha | digit ]
lowalpha             = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" |
                       "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" |
                       "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" |
                       "y" | "z"

Markets

Market paths start with the word "market", followed by two asset_id_or_symbols.

Example: market/BTS/BITUSD

market_path = "market" "/" asset_id_or_symbol "/" asset_id_or_symbol

Public Keys

Public Key paths start with the "public_key" word, followed by bitshares_public_key.

A label parameter MAY be present.

Example: public_key/BTS7T2swLv3QqBAzP1hByB5khUjNFEahtp1fYEHL2GFubMvNGVXyG?label=nathan

Client guideline: add key as a blind contact with label provided.

public_key_path      = "public_key" "/" bitshares_public_key
bitshares_public_key = "BTS" 50*[ base58 ]

Operations

Operation paths start with the word "operation", followed by operation_name (such as "transfer"), with all and any of the operation parameters as params part.

Example: operation/transfer?to=init0&from=fox&asset=BTS&amount=1.3

Client guideline: open an interface to perform described operation, pre-populate input fields with parameters provided.

operation_path = "operation" "/" operation_name
operation_name = "transfer" | "limit_order_create" | "limit_order_cancel" |
                 "call_order_update" | "fill_order" | "account_create" |
                 "account_update" | "account_whitelist" | "account_upgrade" |
                 "account_transfer" | "asset_create" | "asset_update" |
                 "asset_update" | "asset_update_feed" | "asset_issue" |
                 "asset_reserve" | "asset_fund_fee_pool" |
                 "asset_settle" | "asset_global_settle" |
                 "asset_publish_feed" | "witness_create" |
                 "witness_update" | "proposal_create" |
                 "proposal_update" | "proposal_delete" |
                 "withdraw_permission_create" | "withdraw_permission_update" |
                 "withdraw_permission_claim" | "withdraw_permission_delete" |
                 "committee_member_create" | "committee_member_update" |
                 "custom" | "assert" |
                 "committee_member_update_global_parameters" |
                 "vesting_balance_create" | "vesting_balance_withdraw" |
                 "worker_create" | "balance_claim" | "override_transfer" |
                 "transfer_to_blind" | "blind_transfer" |
                 "transfer_from_blind" |
                 "asset_settle_cancel" | "asset_claim_fees"

Here, parameter names MUST match the operation parameters. For example, classic Transfer operation has the following fields in the BitShares specification: from, to and memo. Therefore, same parameter names MUST be used when forming an URL.

Deep objects MAY be represented via extended URL parameter syntax, for example, in BitShares, amounts are usually encoded as:

amount: { "asset_id": <asset_id>, "amount": <atomic_integer> }

This MAY be represented as ?amount[asset_id]=1.2.0&amount[amount]=255.

Wallet software SHOULD respect such notation, making the process of adding new operations to the scheme seamless.

However, for simplicity sake, a shortening method SHOULD be implemented. Continuing with the amount example, a transfer operation MAY paramterize as

asset=<asset_id_or_symbol>
amount=<decimal_amount>

Similarly, the memo field COULD be plain-text, and not the whole object.

A conversion table is provided below:

Operation URI Parameter Operation Parameter
transfer asset=SYMBOL amount[asset_id]=ASSET_ID
transfer amount=DECIMAL amount[amount]=ATOMIC_INTEGER
transfer memo=CLEARTEXT memo[message]=CIPHERTEXT, memo[nonce]=NONCE, ...
limit_order_create sell_asset=SYMBOL asset_to_sell[asset_id]=ASSET_ID
limit_order_create sell_amount=DECIMAL asset_to_sell[amount]=ATOMIC_INTEGER
limit_order_create buy_asset=SYMBOL min_to_receive[asset_id]=ASSET_ID
limit_order_create buy_amount=DECIMAL min_to_receive[amount]=ATOMIC_INTEGER
override_transfer asset=SYMBOL amount[asset_id]=ASSET_ID
override_transfer amount=DECIMAL amount[amount]=ATOMIC_INTEGER
vesting_balance_withdraw asset=SYMBOL amount[asset_id]=ASSET_ID
vesting_balance_withdraw amount=DECIMAL amount[amount]=ATOMIC_INTEGER
asset_issue asset=SYMBOL asset_to_issue[asset]=ASSET_ID
asset_issue amount=DECIMAL asset_to_issue[amount]=ATOMIC_INTEGER
asset_issue to=ACCOUNT_NAME issue_to_account=ACCOUNT_ID
asset_issue memo=CLEARTEXT memo[message]=CIPHERTEXT, memo[nonce]=NONCE, ...
asset_fund_fee_pool asset=SYMBOL asset_id=ASSET_ID
asset_fund_fee_pool amount=DECIMAL amount=ATOMIC_INTEGER
asset_reserve asset=SYMBOL amount_to_reserve[asset_id]=ASSET_ID
asset_reserve amount=DECIMAL amount_to_reserve[amount]=ATOMIC_INT
account_update vote_for=OBJECT_ID new_options[votes][ ]=VOTE_FOR_ID
account_update vote_against=OBJECT_ID new_options[votes][ ]=VOTE_AGAINST_ID

Each operation MAY also have an optional fee_asset parameter, with desired asset_id_or_symbol of the fee asset.

Operation names are defined here:

http://docs.bitshares.org/tutorials/construct-transaction.html#_CPPv2N8graphene5chain9operationE NOTE: ATOMIC_INTEGER specified here and above refers to indivisible "satoshi" amounts of tokens, as used internally on BitShares blockchain.

Blind Receipts

Blind Receipt paths start with the word "blind_receipt", followed by base58_blind_receipt. Client guideline: it might be a good idea to try and accept such blind transfer.

blind_receipt_path   = "blind_receipt" "/" base58_blind_receipt
base58_blind_receipt = base58 *base58
base58               = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" |
                       "9" | "A" | "B" | "C" | "D" | "E" | "F" | "G" |
                       "H" | "J" | "K" | "L" | "M" | "N" | "P" | "Q" |
                       "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" |
                       "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" |
                       "i" | "j" | "k" | "m" | "n" | "o" | "p" | "q" |
                       "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" |
                       "z"

Block / TRX / Operation path

Block / TRX / Operation paths all start with the word "block", but can point to either a whole block, either a transaction in that block, either an op within that transaction (with virtual op to help navigate). Examples are:

block/2333 (points to block 2333)
block/2333/6 (points to tx 6 in block 2333)
block/2333/6/0 (points to op 0 in tx 6 in block 2333)

Client guideline: show block explorer, highlight operation.

block_path   = "block" "/" block_num [ "/" trx_in_block [
            "/" op_in_trx [ "/" virtual_op ] ] ]
block_num    = digit *[digit]
trx_in_block = digit *[digit]
op_in_trx    = digit *[digit]
virtual_op   = digit *[digit]

Transaction by hash

Example: transaction/35212ab2cf4683202e10c16516f5ea64637d7d47 Client guideline: show transaction on block explorer.

transaction_path = "transaction" "/" transaction_hash
transaction_hash = 40*[ alpha | digit ]
alpha            = lowalpha | hialpha

A note on client guidelines

BitShares clients MUST NOT act on URIs without getting the user's authorization. They SHOULD require the user to manually approve each operation individually, though in some cases they MAY allow the user to automatically make this decision. Specific guidelines listed in this BSIP for each URI type are mere suggestions, clients MAY choose to select their own behaviors.

Operating system integration

Graphical BitShares clients SHOULD register themselves as the handler for the "bitshares:" URI scheme by default, if no other handler is already registered. If there is already a registered handler, they MAY prompt the user to change it once when they first run the client.

Discussion

A shortening scheme was proposed, during the discussion, which allows to replace each path_type string with a shorter version. It would win us some bytes in the URL, although it would also make parsers a bit harder to write. The proposed short versions are:

full type short type
object ob
operation op
block bl
transaction trx

In addition, instead of spelling out operation type (e.g. "transfer"), it's id number could be used (so the operation/transfer?to=... could be shortened to op/0?to=...). Some concerns were raised about the (byte-) length of the URI, in particular relation to QR code generation. It should be noted, that long URLs are not really a problem, and the QR code standard makes it possible to encode very long messages without any troubles. For reference, Monero (a popular cryptocurrency) wallet addresses are 95 bytes long, and their URLs look like monero:4AgaTcpcQkXdmwtJnzX62r9vG8idcn6q845uoeh7mcfKehLcSrMi1zdJDZDJudMnNR3gK4PmKV4gXCyX7L1NUc3Y8aMNTvp?tx_amount=0.00123 this. In contrast, a transfer operation bitshares:operation/transfer?to=very_long_account_name&asset=BTS&amount=0.00123 from this BSIP, takes only 79 bytes, yet expresses much more data.

Summary for Shareholders

Adding an agreed-on standard for the URI schema will allow different BitShares software to interoperate and share data on user interface level. It will also enable potential support for QR codes, to be used for payments, sharing contacts, and other features.

Copyright

This BSIP is placed in the public domain.

See Also

Prior work, bitshares1 XTS URLs: https://github.com/bitshares/bitshares1-core/wiki/XTS-URLs

jhtitor commented 5 years ago

This BSIP tries to unify several different ideas, and as such I personally don't agree with everything on it.

In particular, the operation/ -> op/ shortening scheme looks a bit troublesome, and I'd actually vote to remove it.

The bitshares2 name for the protocol is not something I hold particularly dear either, but I think it makes sense, given the history of BitShares.

xeroc commented 5 years ago

The bitshares2 name for the protocol is not something I hold particularly dear either, but I think it makes sense, given the history of BitShares.

Given that we call it "BitShares" today, I am not sure it makes any sense adding it to the URI scheme. If you want to process this in a QR code, those bytes can be spared easily.

Other than that, I like this proposal! +5%

ryanRfox commented 5 years ago

If the URI requires protocol, I'd rather specify bitshares rather than bitshares2. Great work on this spec. I'd like to get some comments from others, but it seems close to me.

jhtitor commented 5 years ago

Thanks for the reviews!

I've updated the text with the following:

Looking forward for more comments and suggestions.

Also, I think, that if we do agree, on the "shortening scheme" ("operation/transfer"->"op/0", from the "Discussion" section) it should be moved to the text proper, and if we don't, a word or two about the rationale should be added (e.g. "it can win us some bytes, but in the end, not worth it"). Please tell me what you think, and I'll do either this or that.

jhtitor commented 5 years ago

Some additional changes:

*For making "vote for this worker/committee member/witness"-type links, for example: bitshares:operation/account_update?vote_for=1.14.0

pmconrad commented 5 years ago

Very good. Some remarks:

jhtitor commented 5 years ago

@pmconrad, thanks a lot for your review. I'm especially grateful that you took time to review the BNF.

ATOMIC_INTEGER is normal integer (which is, as you said, indivisible too), I was just trying to drive the point home -- that it is NOT a float, and that we're talking about "satoshi" amounts of tokens. I also believe that's what those values are (informally) called in bitshares-core code, and in some other cryptocurrencies. I'll think about rewording this somehow.

Edit: OK, text updated. Note, that I'm using same BNF syntax as in RFC1738, so I'm writing digit *[digit] instead of digit+. Hopefully you don't mind, the meaning is the same. I've also found similar problem (single digit instead of a sequence) in transaction path definition, fixed that too. Also added a comment regarding ATOMIC_INTEGERS, is that better?

pmconrad commented 5 years ago

Thanks. Yes, that clarifies it.

Some more things:

I'm unsure if it would be better to allow both upper- and lowercase letters in the URL and specify that they must be converted to the appropriate case by the client.

jhtitor commented 5 years ago

@pmconrad, you have a keen eye :) Thanks.

I've managed to include most of those rules, but some things like size constraints (especially maximum length) are hard to express with BNF. I've also added a note explaining that bitshares-core is the authoritative source for those rules and not this spec (e.g. "ASSET.SUBASSET" did not always exist, and I imagine more mutations might appear in the future).

I don't think we should get too overboard with constraining the URLs, and we probably should actually allow any kind of garbage in there, to be dealt with other layers of the software (e.g. "account/12improper___NAME" could just yield "no such account" error on a higher level). Just a thought, though; like I said, I've updated the text, implementing most of your remarks.

bitshares_public_key -- Not sure if that's always exactly 50 digits.

It is, as far as I know.

pmconrad commented 5 years ago

Thanks again. I agree that it might be better to be lenient with the URL. Account or symbol names that do not match the chain rules should be treated as nonexistent.

sschiessl-bcp commented 5 years ago

I don't think we should get too overboard with constraining the URLs, and we probably should actually allow any kind of garbage in there, to be dealt with other layers of the software

Sounds acceptable IMO

sschiessl-bcp commented 5 years ago

Original discussion and references are here https://github.com/bitshares/bitshares-ui/issues/775

Bill was quite persistent in being compatible to an easy-to-use transfer abbreviation, which I tried to incorporate through another conversion.

Summary: bitshares:someaccountname (important that this string contains no /) is an abbreviation for operation/transfer?to=someaccountname

Is that format something that is already well-known/established for other blockchains (bitcoin)? If so, I think we should adopt it. Thoughts?

pmconrad commented 5 years ago

Hm. I don't see why bitshares:account_name should specifically indicate a transfer operation. It feels much more natural to treat it as an account path.

Or perhaps bitshares:lowercase_string -> bitshares:account/lowercase_string and bitshares:uppercase_string -> bitshares:asset/uppercase_string.

As in Vote for bitshares:cyrano now!!!. Or Feed producers needed for bitshares:HERTZ.

jhtitor commented 5 years ago

bitshares:someaccountname (important that this string contains no /) is an abbreviation for operation/transfer?to=someaccountname Is that format something that is already well-known/established for other blockchains (bitcoin)?

Yes, it is. Bitcoin, all bitcoin-derived coins, and other "simple" coins all use this notation. By "simple", I mean coins that only support one type of operation -- a transfer. In such coins, no ambiguity is present at all.

If so, I think we should adopt it. Thoughts?

Personally, I agree with abitmore in regards to the original discussion: bitshares is not a "simple" blockchain, we have 40+ operations, and I think it helps to be as explicit as possible. In short: no, I don't think we should adopt it.

Or perhaps bitshares:lowercase_string -> bitshares:account/lowercase_string and bitshares:uppercase_string -> bitshares:asset/uppercase_string.

This sounds very dangerous, 1 case conversion function on either end can cripple the meaning beyond recovery (there are certainly accounts and assets with the same name, I'm thinking gateway accounts and gateway base coins).

I understand the wish to be similar to other coins, and also for an easy-to-write-by-hand URLs, but I also think it's just not worth it, given the dangers.

(Yet again: I'm just a humble servant, and will readily adopt the spec to your liking, but I believe abitmore made very good points, and I wrote this BSIP with them in mind).

sschiessl-bcp commented 5 years ago

In short: no, I don't think we should adopt it.

Alright by me. If anything, another abbreviation is not that hard to add, or support as "outside this BSIP". Would you care to meld this into a PR now?

jhtitor commented 5 years ago

@sschiessl-bcp, done. Should this issue be closed now?

ryanRfox commented 5 years ago

Assigned BSIP60. Looking for confirmation from Reviewers of the PR to merge it. We will leave this Issue open until the BSIP status advances from draft.

pmconrad commented 5 years ago

I don't think this will ever leave "Draft" status. It's an informational BSIP. We don't vote on these, do we? Closing, feel free to reopen if you disagree.

sschiessl-bcp commented 5 years ago

I don't think this will ever leave "Draft" status. It's an informational BSIP. We don't vote on these, do we? Closing, feel free to reopen if you disagree.

I agree, some way of leaving draft status would be nice anyways. Any ideas?

Informal voting? "developers agreed"-status?