Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QIP-5: Signature proofs within vout scripts for contract transactions #6

Earlz opened this Issue Nov 29, 2018 · 0 comments


None yet
1 participant
Copy link

Earlz commented Nov 29, 2018

This is written as a counter proposal to QIP-2.


With this QIP, it would be possible for a user to sign and prove their identity to a contract without owning any UTXOs/coins owned. This would primarily be useful only to contracts so that msg.sender can be set to an address that owns no coins or UTXOs. This would not allow free transactions, someone else must still pay for the transaction to be placed into the blockchain


The way contracts figure out who sent the message (and authenticate it) is to check “ok, did this person spend a UTXO in this transaction” (even if they merely spent it and sent all the funds back to themselves). This sounds a bit wasteful, but the worse problem is that without a UTXO it’s impossible to authenticate that you’re sending a message to the contract. Even if someone else pays the fees and everything else for you, you still need a UTXO to really do anything with most contracts. This issue commonly comes up in other cases as well. Your wallet has multiple addresses and each address has it’s own set of UTXOs. The blockchain is incapable of knowing that those addresses belong to the same wallet. So, what happens when you choose to send QRC20 tokens to some certain address, but then find out that address has no UTXOs. You will be incapable of spending the QRC20 tokens, since you have no way of proving to the contract that you are that certain address. The official workaround for this problem is to simply send that certain address any amount of coins (even 1 satoshi) so that it has a UTXO, and then you can withdraw your QRC20 tokens or whatever. Later, Qtum Core will (by default) make sure to use change addresses to ensure that address always has a UTXO.

This is wasteful of precious UTXO set space, but most of all it’s incredibly annoying for user experience of both Dapps and Qtum users.


A new opcode named OP_SENDER will be added. This opcode is only valid when used within vouts that contain either an OP_CALL or OP_CREATE opcode. OP_SENDER takes three arguments:

  • UniversalAddress type -- the type of sender
  • UniversalAddress data -- the address data for the sender (to account for this later being dynamic length)
  • scriptSig -- the serialized scriptSig necessary to complete the signature of the address

Example vout

1 // pubkeyhash address type
address // pubkeyhash address
{signature, pubkey} //serialized scriptSig pushed
1 //EVM version
10 //gas price
100000 //gas limit
1234 //contract data to send

OP_SENDER will cause an internal script execution. It will fail if the end result is not 1. For this example, it would look like so:


The serialized scriptSig would be treated the same as if it were a normal scriptSig for validation purposes. If the end result evaluates to 0, the transaction is invalid and can not be included in a block. For pay-to-scripthash senders, the scriptSig would be treated the same as normally, with the script being executed twice. First, to check the hash is the same as the scripthash, and then again to execute the redeemScript for spending P2SH outputs.


The actual data to be signed will be a special case. Normally in Bitcoin and Qtum, only scriptSig scripts within the vin contains signatures, thus it is easy to come up with a signing scheme to avoid the "signing signed data" problem. However, this scheme breaks that assumption by having signatures inside of vout scripts. In order to avoid breaking existing Bitcoin based paradigms, signing will thus be split into two separate steps:

  • Sign vouts containing OP_SENDER
  • Sign vins

The vin signing process will be untouched, and thus signatures within the vouts will be signed by vin signatures. This is suboptimal, but is much safer and less complex.

The vouts will be signed as normally done for vins, but with the OP_SPENDER scriptSig changed to a zero size value. See for the signature signing schemes. The following modifications must be made however:

  • ANYONECANPAY -- Only the first vin will be signed
  • ALL/NONE/SINGLE -- All vins will be signed
  • NONE -- invalid and/or non-standard. There is no practical use for this, as even the current output would not be signed. Any data could be sent as the specified sender by modifying the vout data after
  • SINGLE -- only the current vout will be signed
  • ALL -- all vouts will be signed


This method supports all of the features of the previous iteration of this proposal while including the following improvements:

  • Significantly less likely to affect consensus. No modifying code that has never been touched, constrained functionality to only contract containing transactions
  • Same transaction format and functionality with no specialized meanings
  • No risk of a bug potentially allowing a UTXO set spam attack
  • Allows for multiple contract executions to happen in a single transaction with different senders for each one
  • Allows for less back and forth for proposed fee-provider and dapp-fee-paid services
  • Should be significantly easier to implement
  • Extensible to support any UniversalAddress type in the future

However, it does carry the following downsides:

  • Special signature attaching tools and RPC calls must be supplied to make use of this functionality
  • Vout scripts must be checked for OP_SENDER and parsed to remove the scriptSig field when checking signatures. Normally vout scripts can be left alone when doing signature checking


This would require a hardfork and could potentially be bundled into the x86 hardfork in 2019.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.