lbryio / lbrycrd

The blockchain that provides the digital content namespace for the LBRY protocol
https://lbry.com
MIT License
2.58k stars 178 forks source link

Purchase Transactions (claim identifier in transactions) #184

Closed kauffj closed 6 years ago

kauffj commented 6 years ago

There should be a special transaction type to indicate that a transaction is to purchase the rights to a piece of digital content.

This would only differ from a normal transaction in two ways:

1) It would include the claim_id of the content intended to be purchased. 2) When a claim_id is included, a miner will reject the transaction if: a) the associated claim metadata is invalid b) the destination address does not match the fee_address c) the transaction amount is smaller than the fee_amount (but how to handle non-LBC denominated fees??)

BrannonKing commented 6 years ago

To summarize our discussion: can we enforce that all claims are in LBC when they reach lbrycrd?

kauffj commented 6 years ago

Enforcement of LBC should definitely be possible, though would involve adding lbryschema to lbrycrd.

The trickier part is non-LBC denominated purchases, which would presumably require outside network information.

kaykurokawa commented 6 years ago

This does not seem to be an appropriate solution on the blockchain layer.

Maybe I'm misunderstanding the point , but please clarify further why you'd need a special transaction that handles the purchasing of rights to digital content. Why is a normal transaction insufficient?

kauffj commented 6 years ago

The claim_id needs to be embedded in the transaction so that we can know what piece of content the purchase was for. The wallet address is insufficient.

If we're embedding the claim_id, it seemed logical (assuming feasibility), to make this type of transaction also attempt to enforce that the transaction is for a sufficient amount.

kaykurokawa commented 6 years ago

I believe the original reason why the wallet address is insufficient was this:

a) electrum was very limited in its ability to handle a large number of addresses (as address size grew, it became very slow to sync).

b) we fixed this problem by using a single address as a receive address for all content payment.

So if our new wallet code ( paging @eukreign , what is the additional duration that is needed to sync torba for each address ? ) doesn't have problem a), we can have clients assign unique addresses to specific content and this problem is solved without the blockchain layer.

kauffj commented 6 years ago

This has nothing to do with performance. A wallet address is not the value that corresponds with a unique piece of digital content. We decided that the value that uniquely corresponds to a piece of digital content and never changes is the claim identifier. That is what needs to be recorded. There should be no possibility of ambiguity and this should be handled in a hard way (i.e. not a convention).

kaykurokawa commented 6 years ago

a) " A wallet address is not the value that corresponds with a unique piece of digital content." - neither is the claim_id if the digital content can be changed to anything through the metadata.

b) What is the purpose of recording purchases to a claim identifier on the blockchain? What does this achieve?

tzarebczan commented 6 years ago

A) that is true, but this would still be a valid indicator that something was purchased for that particular claim.

B) a user who receives the payment will know what content it was for, and same goes for the person sending it (right now they just see a receive or send tx without any information).

Are you saying the above would be possible to track just by creating a tx that associates the claim ID without making blockchain changes?

kauffj commented 6 years ago

A) Yes, but this is up to the publisher and no one else, so this the best of all possible solutions. And the claim_id cannot be changed arbitrarily, so while the publisher can change it, it's not as if they can set it to match another publish.

B) The purpose is to have a transaction that unambiguously proves you purchased the rights to a specific piece of content.

eukreign commented 6 years ago

BIP70 might be relevant to this issue since it includes proof of payment: https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki

lyoshenka commented 6 years ago

@kauffj instead of suggesting a particular solution, could you rewrite the issue from the point of view of a non-dev user, with things like acceptance criteria, constraints, motivation, who wants this and why, etc. It will help us figure out the right way to do this

kauffj commented 6 years ago

@lyoshenka putting the claim id in the transaction is the feature.

I could write this more generically and say something like "include a unique identifier corresponding to a piece of content in a transaction", but I'm unclear on how that would improve anything.

eukreign commented 6 years ago

2c. If the fee is hard coded in the metadata and enforced at blockchain level how would you do discounts (or free to specific individual, for example, someone lost their wallet and asked you to be given the content on a new wallet and you decide to give them the content free of charge, there are many other situations like this)? Seems like it would be more robust if the negotiation happens off chain and only the proof of ownership is recorded on chain?

kauffj commented 6 years ago

I agree that 2(c) is a difficult and potentially impossible problem.

Even if we cannot reject transactions based on the validity of the amount, it is still useful to include the claim_id in the transaction.

lyoshenka commented 6 years ago

what are the use cases for having the claim id in the transaction? is it for reporting to content creators? for not having to pay for the same piece of content multiple times? anything else im missing?

tzarebczan commented 6 years ago

Also, the person paying for it will see what they claim they paid for (goes along with your 2nd point)

eukreign commented 6 years ago

One of the main benefits I can see of this feature is being able to re-establish ownership of all of your purchased assets at the same time as you are re-creating your wallet from a seed.

If the negotiation will happen off chain then the on chain portion has to somehow include approval from both parties of the agreement (buyer offering to buy ownership in exchange for something or nothing and seller agreeing).

But if seller has to perform some blockchain operation to approve a sale this doesn't seem to scale well.

eukreign commented 6 years ago

You could have an off chain operation where you have the seller sign your transaction (approving it) and then this goes on the blockchain. For example:

  1. Buyer creates a purchase output;
  2. sends it to seller to be signed;
  3. seller either automatically agrees or there is some negotiation that happens;
  4. seller sends the signed output back to buyer;
  5. buyer adds the signed output to a TX, signs the tx inputs and then broadcasts it.
  6. block chain will have proof of both parties agreement (seller signed output; buyer signed inputs) and the claim_id in the output would point to what was purchased.
eukreign commented 6 years ago

It would also be very useful to know the possible ways in which ownership will be enforced, knowing this might influence how ownership is established and recorded.

lyoshenka commented 6 years ago

i don't think the seller needs to be involved. if there's a claim for some content and it has a price, and you broadcast a transaction that contains the claim id and spends the appropriate amount to the claim's fee address, that's a sale. what would we gain from the seller signing it?

lyoshenka commented 6 years ago

that said, the blockchain is unaware of the metadata. if we add any kind of validation at the blockchain level, it would become very difficult to change the structure, add fields, etc. so i don't think that's possible.

kauffj commented 6 years ago

@lyoshenka the ability for the blockchain to read/parse/execute against metadata would not necessitate full validation of the metadata

eukreign commented 6 years ago

Without seller involvement you can't:

  1. offer different prices or discounts
  2. donate a piece of content to someone
  3. limit number of purchases (eg. you are selling a stream subscription and only wanted max 50 subs)
  4. claim it's an actual sale

If you consider a sale to be a contract between two parties then there needs to be agreement/consent on both sides. Blindly sending money to someone and then demanding they deliver a product is not a legal contract. https://www.lawteacher.net/free-law-essays/contract-law/one-sided-contract.php

Really great presentation on what is a contract (Offer+Acceptance+Consideration): https://www.youtube.com/watch?v=2Mqn_RxRj84

eukreign commented 6 years ago

Other things to consider (and this would be affected by what the enforcement mechanism is):

  1. can you be refunded?
  2. how do you differentiate a refund from the seller just spending your payment as a regular UTXO? (for example, you buy something and then that person turns around and buys something from you spending the same UTXO that formed your initial purchase with them, how would you differentiate between that and a refund?)
  3. can you transfer the ownership to someone else?
  4. will we ever want to support escrow?
roylee17 commented 6 years ago

How about just using the (Null Data) OP_RETURN "output", which carries up to 80 bytes of data. A transaction to be considered "Standard" can have at most 1 Null Data output. The block explorer would list that OP_RETURN output as hex code.

In this case, 1) the claim_id (and/or other transaction detailed) can be associated with the transaction. 2) The business logics can be processed off-chain.

kaykurokawa commented 6 years ago

Ok, there's many reasons why this proposal still doesn't make sense to me. Here's three issues:

A) Others have said this but this proposal only covers one method of paying for digital content (in LBC, and only when paying a fixed amount as determined by the metadata in a privacy destroying manner). Note that ideally any privacy retaining purchases of digital content happens off the chain (you'd probably negotiate with the seller's server instead of making a payment to a fixed address/claim id)

B) The mistake is thinking that Claim ID is somehow permanently associated with unique digital content. That is not the case because content attached to claims can be altered in any way that the claim owner desires. Have we even established that each claim to a name shall offer unique digital content? Say fox claims rights to the name Simpsons, and their plan is to publish new Simpsons episode on that claim every week. This is a sensible use of name claim updates where the digital content changes every week. There are of course insensible uses where claim owners just change it to whatever the heck they want, maybe someone thinking they are purchasing rights to a harry potter book have now magically purchased rights to big foot erotica ( the worse news is that everyone in the entire world can also see you purchased rights to big foot erotica).

C) Every use case that can be established with the proposed "transaction, but attached with claim id information", can be achieved through simply attaching unique payment addresses to metadata of digital content. Since payment addresses can be updated on name updates, it is better than using claim ID's (but also suffers from the same privacy concerns). If this method is not sufficient, it needs to be explained why.

eukreign commented 6 years ago

A) Only supporting LBC is a feature, not a bug? Can we just make it easy to convert from fiat/other-coin to LBC on the client side before proceeding with the purchase?

B) This is a really good point; I'll see if I can solve this in my proposal (perhaps by including a txid:nout of the latest claim_id at the time of purchase, ultimately it will be up to the content gate keeper to decide which version of claim to release based on presented proof of purchase and proof of ownership).

C) I agree with you that using designated address to collect payments is a good way if the goal is to protect privacy and have something working today (it already works today). The biggest issue with this approach is that you can't restore your purchased content from a seed (at least not right now).

I'd propose that we offer two solutions with drastically different pros/cons:

  1. A privacy conscious option using the approach you've outlined with a designated address to which payments are sent and there is no way to find out who bought what. This has the downside that you can't prove you bought something and you can't easily re-construct your assets from scratch using only a seed.

  2. A less privacy concious option but where you get an actual proof of purchase recorded on the blockchain and it's straight forward to reconstruct your purchases when recreating wallet from seed. Although, I'd argue that it would still take a bit of effort to figure out who bought what looking from the sidelines: someone would have to prove that the address from which the TXI came from is yours or what identity is associated with the proof of purchase.

kauffj commented 6 years ago

A) Yes, this is only for LBC. Note that we currently only process payments for content in LBC. I agree that it is not clear how we would handle all possible cases right now, but I would rather operate under the assumption we will eventually solve these than to use the lack of a perfect solution as a reason to not make any progress.

B) I think everyone in this thread understands this completely. This is not a problem. If the publisher choose to update a claim rather than make a new one, they are by our definitions saying it is the same content. Yes, they could lie. This is already true today and similar to A, I do not understand how this is an argument against recording the claim_id.

Today, in the real world, Disney could today release a movie called "Star Wars: A New Hope" that only contains Bigfoot erotica and simultaneously stop selling "Star Wars: A New Hope" that contains lightsabers and spaceships. It would be pretty clear to ascertain which "Star Wars: A New Hope" you purchased by the date of the purchase.

C) If there is a superior design to claim_ids, I'm fine with replacing them. If you're not proposing dropping them entirely, I'm confused as to why we would want two different values to serve the same purpose.

kauffj commented 6 years ago

Also, all privacy concerns seem out-of-scope to this discussion. I'm for improving private usage of LBRY, but I don't see how it relates to this ticket. Transactions are already public. If you want to use LBRY privately, you'd simply conduct your transactions in a way that doesn't make them traceable to you. Whether or not claim ids are included seems unrelated.

eukreign commented 6 years ago

I've moved the write up I did in slack over to the proposal repo and cleaned it up significantly: https://github.com/lbryio/proposals/issues/6

I've added a new <claim_version> value which is the hash of txid:nout of either the original CLAIM output (which means claim_id==claim_version) or of the latest UPDATE of the claim. The BUY includes both the claim_id and the claim_version.

Lbrycrd should hard fail if the claim_id in the BUY transaction is not equal to the same in the SELL transaction but I leave the claim_version verification up to the seller. The logic there is that if you are selling something and you don't tie it to a specific version of the claim then you are promising to provide either the latest version or any version, seller could also hard fail the TX if they only want to sell a specific version of the claim and buyer has requested one that isn't that one. Therefore the default behavior is a little open ended but there is room to tie it down should that make sense in a particular sale.

kaykurokawa commented 6 years ago

C) I agree with you that using designated address to collect payments is a good way if the goal is to protect privacy and have something working today (it already works today). The biggest issue with this approach is that you can't restore your purchased content from a seed (at least not right now).

I don't think being able to restore purchased content from a seed is a necessary feature, but there is technically no obstacle to restoring content from seed if you use unique addresses.

It would be pretty clear to ascertain which "Star Wars: A New Hope" you purchased by the date of the purchase.

Actually no because the user does not control the time that a transaction enters the block, the miner (and network delay) does. You'd have to use unique addresses in the metadata, or the txid:nout as lex suggested in order to truly specify which unique content you are referring to.

kauffj commented 6 years ago

@kaykurokawa txid:nout is not a unique piece of digital content. It corresponds to a specific version of a unique piece of digital content. To clarify via example: this last season of Westworld, an episode was initially shown live with a camera man visible in a shot. The version available on demand 24 hours later did not include this.

We need two separate unique values for:

When I purchase a piece of content I am purchasing the thing that corresponds with the claim_id, not the outpoint. When a publisher updates a claim, I am entitled to the new version without paying if I have already purchased the previous one. If they publish a new version with a different claim id, they are stating it is a unique/different piece of content that I would need to re-pay for.

So the claim_id or something equivalent to it is what needs to be recorded.

I do not see how an address can replace a claim id, as there are operational or security reasons that one might want to update or change an address without intending to say they have created an entirely new piece of content.

kaykurokawa commented 6 years ago

When I purchase a piece of content I am purchasing the thing that corresponds with the claim_id, not the outpoint.

When a publisher updates a claim, I am entitled to the new version without paying if I have already purchased the previous one. If they publish a new version with a different claim id, they are stating it is a unique/different piece of content that I would need to re-pay for.

This is just your vision of how the system should work. I'm not saying that its incorrect, I'm saying that this vision is not enforceable on the blockchain layer because we cannot prevent people from using that layer however they want. Attaching claim ids, or whatever, to transactions will not help you enforce this system.

So the claim_id or something equivalent to it is what needs to be recorded.

What I'm trying to say is that there is no such "equivalent" that can be constructed in the blockchain layer because it implies that the blockchain layer can understand what a digital content is, or what rights to digital content means. All it understands really is claims to names. If we make a transaction type that attaches claim id's or whatever to a transaction, it does not mean we created a transaction type that handles the purchases of digital content. It just means we made a transaction type that has an attached claim ID. This could mean a wide variety of things.

And remember again that we cannot stop people from using the blockchain layer however they want. This means that if people do not use this new transaction type the way you envision it, it will break whatever system and abstraction we have built on top of it.

eukreign commented 6 years ago

In my buy/sell transaction proposal there is blockchain enforcement of an agreement between both parties resulting in a valid proof of purchase being recorded. Therefore, the blockchain adds extra metadata which is otherwise not present in the simple values included with the transaction: agreement from both parties on the validity of the proof of purchase.

If the BUY transaction makes it into the blockchain then the purchase is now binding. What it means for it to be "binding" is up to the parties but they both had to take steps to make it possible for the BUY to be recorded.

Doing this on chain is meaningful.

kauffj commented 6 years ago

This is just your vision of how the system should work. I'm saying that this vision is not enforceable on the blockchain layer because we cannot prevent people from using that layer however they want.

No, it is how LBRY works today. Publishers are agreeing to this when they submit a publish to the LBRY protocol and it is how all properly implemented software behaves, including ours. Whether or not the blockchain enforces it is irrelevant.

If a publisher issues a claim update, it is the user's right to re-download the new content without paying. The daemon does this today.

If a publisher issues a new, non-free publish with a different claim id, the user must pay to access this content in order to access it legally. The daemon does this today.

It doesn't matter that the blockchain cannot tell if a piece of content is the same; it is fine to put this responsibility on the publisher.

What I'm trying to say is that there is no such "equivalent" that can be constructed in the blockchain layer because it implies that the blockchain layer can understand what a digital content is, or what rights to digital content means.

As covered above, you are misunderstanding what is necessary here for this to be useful. The blockchain does not need to understand what a piece of digital content is, nor does it need to understand what rights are.

If a user can produce a valid transaction that includes a claim id for an amount that is larger than or equal to the price of the content at the time of the transaction, this is proof the user made a valid purchase of the content.

The fact that someone could potentially falsely embed a claim id does not make the above invalid. A claim id being embedded in a transaction is a necessary condition for proof, not a sufficient one.

Without claim ids (or equivalent value) being embedded in a transaction, there is NO sufficient way to show proof because a publisher may have re-used the same address.

kaykurokawa commented 6 years ago

Yes notice how these features/workflow in LBRY are implemented in the daemon. The blockchain provides the "transaction" and "claim name" abstraction while the DHT provides the "content" abstraction so the daemon is the place where these user work flow is implemented.

Let's talk about creating a "proof the user made a valid purchase of the content." This does not require the blockchain layer to do anything. There is a private key associated with the transaction, all that is needed is for the user to sign a message that says "I am paying for the digital content associated with this unique identifier". This message does not need to be validated by the blockchain layer, or even be in the blockchain. The reason is that all the validation can be performed off chain by retrieving the metadata from the unique identifier and than checking to see if the transaction that was created is formed as specified by the metadata.

This is a superior method because it can potentially handle any kind of alternative payment methods involving discounts and what not, and even non LBC payment methods. In addition, the blockchain layer, which is the most annoying place to make changes, is unaffected. We can implement this into the daemon layer and not worry that our blockchain is going to fork because we made a massive consensus breaking change, we can easily change the metadata format without worrying too much about backwards compatibility, we can easily add new features, and we don't have to worry that we are imposing too much of a computational burden on the full nodes, etc..

Perhaps once we have properly defined what is exactly the feature that we want and explored all its use cases, the message that I described could be inserted into the blockchain layer and even be validated by the blockchain layer. I'm not convinced this is a good idea, but even if it was there is much work that needs to be done. At this point the blockchain layer doesn't even understand what a metadata is, beyond the fact that its just data.

Basically, a MVP of this feature can be built purely on the daemon layer with the available constructs (signatures stored in wallets, metadata retrieval through lbryum server), so why not do that first.

kaykurokawa commented 6 years ago

Also note that it is likely unreasonable for every full node to validate the fact that Alice bought a Star Wars movie from Disney. If I'm a full node that is not Disney, I only care that Alice paid money to Disney, in case that either Alice or Disney pays me in the future.

Only full nodes that would care (that a Star Wars movie was bought) is Disney's and maybe some statistic gathering entity. So they should be the only ones burdened to validate this fact, not everyone else. It wouldn't even be a burden for Disney because they have direct access to the metadata for the content they created and they wouldn't even need to go to the blockchain to retrieve that.

kauffj commented 6 years ago

At a minimum, I'll be scheduling time the week of 9/10 to discuss this in person. At a minimum, we are in complete agreement that if there is design uncertainty here, there is a benefit in building an MVP before changing consensus.

@kaykurokawa can you clarify something about this part?

all that is needed is for the user to sign a message that says "I am paying for the digital content associated with this unique identifier"

1) Where are you proposing that this message go and/or be stored? 2) How does this solve the problem of disambiguating between two distinct pieces of content, represented by two distinct claims (with unique ids), that share an address and price? I understand that I could sign a message at the time of purchase differentiating the two, but what would stop me from signing two messages and producing either as is necessary or useful? 3) How would the publisher receive this message and be able to read it? 4) What would "require" (quotes because it probably means something likely "strongly encourage") the user to make this message available to the publisher?

kaykurokawa commented 6 years ago
  1. in the wallet of whoever created the tx, and than sent to whoever you want to prove that you purchased something
  2. there would be no point of doing that as people can verify that the associated transaction does what it is supposed to do according to the metadata.
  3. it can be part of the negotiation process, and mmaybe stored on some central server (i.e. the data server) for later retrieval
  4. this proves to the publisher, you are the creator of the tx, so they will send you the content
kauffj commented 6 years ago

I think I am still misunderstanding some aspect of this idea.

there would be no point of doing that as people can verify that the associated transaction does what it is supposed to do according to the metadata

Doesn't this imply that there is something in the metadata that is analogous to a claim id?

kaykurokawa commented 6 years ago

The proof of purchase contains two parts, the transaction, and a signed message associated with the private key of the transaction that basically says in plain english: "Hey, I Joe Smith (or some other forms of identity like an IP address that allows you to receive said digital content) created this transaction for the digital content associated with the unique ID. You can look up the metadata with this unique ID and verify that indeed the transaction follows the payment method specified by the metadata and pays X amount to X address as specified"

eukreign commented 6 years ago

@kaykurokawa

  1. Where is the message stored?
  2. Why is the message plain english instead of machine readable?
kaykurokawa commented 6 years ago
  1. in user wallet and sent wherever its needed (to the publisher presumably)
  2. i just wrote it that way to be clear. yes in practice its machine readable
eukreign commented 6 years ago

Anything we store in user wallet that cannot be re-created from the seed also means it won't get sync'ed between users devices automatically.

If user buys a movie on their desktop and wants to watch it on their phone during a flight, they will need to remember to manually sync their wallet between their desktop and phone. Conversely, if everything is on the blockchain, then all of their wallets automagically stay in sync all the time (as long as they have an internet connection to a lbryumx / spv wallet server).

Also, I think Disney using LBRY blockchain would be a good thing. If processing the buy/sell transactions on the blockchain makes it easier for Disney to adopt LBRY then we should start on this posthaste! :-D

kauffj commented 6 years ago

@kaykurokawa wouldn't that design require that a wallet address is unique to a piece of content?

As discussed up thread, it's a requirement to have a value that corresponds uniquely to a piece of content that is decoupled from an address (alternatively, we'd need to enforce unique addresses, but this also has downsides).

If a publisher has two distinct pieces of content with the same payment address and the same price, would your design handle this case?

eukreign commented 6 years ago

@kauffj my understanding of the last proposal from @kaykurokawa is that a message is created with all of the details of the purchase and the user must keep this message receipt / proof of purchase in their wallet and produce it each time they want to download content. The link between a user and the content is encoded in this message; therefore the address is no longer important (the same receiving address can be used for all content made by a creator). If you lose this message it cannot be re-created from the wallet seed and you can no longer download content you purchased.

kauffj commented 6 years ago

@eukreign yes, I understand that.

What I don't understand is how it handles the scenario of two pieces of content with identical payment addresses and identical prices.

What prevents me constructing two receipts from a single transaction?

kaykurokawa commented 6 years ago

Here is the non-blockchain solution that I'll propose: https://github.com/lbryio/proposals/issues/8

alyssaoc commented 6 years ago

Issue moved to lbryio/proposals #9 via ZenHub