Skip to content

Conversation

@Christewart
Copy link

This pull request implements the op code OP_WITHDRAWPROOFVERIFY found in the elements project.

The purpose of OP_WITHDRAWPROOFVERIFY is to support sidechains.

To see a detailed description of OP_WPV functionality please read this blog post:

https://medium.com/@Chris_Stewart_5/op-withdrawproofverify-the-op-code-that-powers-spv-sidechains-cefce996a324#.y2dcegslq

This pull request has a generator inside of it to test all cases that should be successful for OP_WPV. We test that generator produces only valid OP_WPV withdrawls here.
TODO:

Modifying generators to be more flexible
Fixing bug in generator for merkle blocks with specific txs
Adding more flexibility to block header generators
… coins in the OP_WPV output when a user is not withdrawing all of them
Fixing bug in calculating pushops for ScriptNumberOperations
…iptNumberOperations -- for instance pushing an 83 byte transaction (whose op code is OP_3) -- whose script looks like OP_PUSHDATA1 OP_3 <83 byte tx> would fail before this
Fixing bug in pushing constants onto the stack whose op codes are Scr…
…pt_num_op

Fixing bug in calculating pushops for ScriptNumberOperations
(sidechainCreditingTx,outputIndex) = TransactionGenerators.buildSidechainCreditingTx(genesisBlockHash, reserveAmount)
sidechainCreditingOutput = sidechainCreditingTx.outputs(outputIndex.toInt)

contract = BitcoinSUtil.decodeHex("5032504800000000000000000000000000000000") ++ userSidechainAddr.bytes
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to use generator here



/** Generator for a contract used within a [[WithdrawScriptSignature]] */
def contract: Gen[Seq[Byte]] = for {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably need to create a type for 'contract' and create a generator that takes in a Sha256Hash160Digest

*/
def opWithdrawProofVerify(program : ScriptProgram) : ScriptProgram = {
// comment from bitcoin core
require(program.script.headOption == Some(OP_WITHDRAWPROOFVERIFY), "Script operation is required to be OP_WITHDRAWPROOFVERIFY")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to implement the flag 'ScriptVerifyMinimalData`, this is implemented in elements but I haven't implemented yet in bitcoin-s-sidechains

/** Checks the given [[MerkleBlock]] to see if we have enough proof of work
* [[https://github.com/ElementsProject/elements/blob/edaaa8b0f92653d9f770e671c7493f4bab4b48c7/src/pow.cpp#L40]]
* */
private def checkBitcoinProofOfWork(merkleBlock: MerkleBlock): Boolean = {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implement this


case object OP_WITHDRAWPROOFVERIFY extends CryptoOperation {
override def opCode = 179
override def toString = "OP_NOP4"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comment to why this is is set to OP_NOP4 and not OP_WPV, same with OP_NOP5

val txSigComponent = program.txSignatureComponent
logger.debug("TxSigComponent: " + txSigComponent)
/** Helper function to check if the witness was used */
def witnessUsed(w: WitnessV0TransactionSignatureComponent) : Boolean = {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider moving this refactor upstream into bitcoin-s-core

(scriptSig,scriptPubKey,fedPegScript,reserveAmount) <- ScriptGenerators.withdrawlScript
(sidechainCreditingTx,outputIndex) = buildSidechainCreditingTx(genesisBlockHash, reserveAmount)
sidechainCreditingOutput = sidechainCreditingTx.outputs(outputIndex.toInt)
sidechainUserOutput = TransactionOutput(scriptSig.withdrawlAmount,P2PKHScriptPubKey(scriptSig.userHash))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not always a P2PKHScriptPubKey, can be P2SHScriptPubKey depending on what the contract specifies.

//TODO: Investigate this further, can we technically have negative output indexes as script numbers can be negative?
UInt32(num.toLong)
case constant: ScriptConstant =>
logger.error("Asm: " + asm)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this logger.error

require(program.txSignatureComponent.isInstanceOf[FedPegTransactionSignatureComponent])
val fPegTxSigComponent = program.txSignatureComponent.asInstanceOf[FedPegTransactionSignatureComponent]

val relockScript: ScriptPubKey = ScriptPubKey(Seq(BytesToPushOntoStack(32),genesisHashToken, OP_WITHDRAWPROOFVERIFY))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call WithdrawScriptPubKey constracut here instead of constructing the asm ourselves.

val partialMerkleTree = merkleBlock.partialMerkleTree
val matchedTxs: Seq[DoubleSha256Digest] = partialMerkleTree.extractMatches

if (partialMerkleTree.tree.value != Some(merkleBlock.blockHeader.merkleRootHash) || matchedTxs.length != 1) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of != I think scala recommends using .contains()

return ScriptProgram(program, ScriptErrorWithdrawVerifyOutputScriptDest)
}

val contractWithoutNonce = contract.take(4) ++ contract.slice(20,contract.length)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After creating a type for 'contract` create a method to access the user's hash

val (sidechainCreditingTx,outputIndex) = buildSidechainCreditingTx(genesisBlockHash)
val sidechainCreditingOutput = sidechainCreditingTx.outputs(outputIndex)
val sidechainUserOutput = TransactionOutput(amount,P2PKHScriptPubKey(usersHash))
val relockScriptPubKey = ScriptPubKey.fromAsm(Seq(BytesToPushOntoStack(32),
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call WithdrawScriptPubKey.fromAsm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant