mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-18 21:34:39 +01:00
Successfully hashing multisig transaction to sign - tested against bitcoinj
This commit is contained in:
parent
2b88e270db
commit
a859d8342d
@ -34,7 +34,7 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
|
|||||||
* @param script
|
* @param script
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def serializeScriptCode(script : Seq[ScriptToken]) : ScriptPubKey = removeOpCodeSeparators(script)
|
def serializeScriptCode(script : ScriptPubKey) : ScriptPubKey = removeOpCodeSeparators(script)
|
||||||
|
|
||||||
|
|
||||||
def serializeInput(input : TransactionInput, nType : Int, nVersion : Int) : String = ???
|
def serializeInput(input : TransactionInput, nType : Int, nVersion : Int) : String = ???
|
||||||
@ -71,7 +71,8 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
|
|||||||
input <- spendingTransaction.inputs
|
input <- spendingTransaction.inputs
|
||||||
} yield input.factory(ScriptSignatureFactory.empty)
|
} yield input.factory(ScriptSignatureFactory.empty)
|
||||||
|
|
||||||
|
inputSigsRemoved.map(input =>
|
||||||
|
require(input.scriptSignature.bytes.size == 0,"Input byte size was " + input.scriptSignature.bytes))
|
||||||
|
|
||||||
// This step has no purpose beyond being synchronized with Bitcoin Core's bugs. OP_CODESEPARATOR
|
// This step has no purpose beyond being synchronized with Bitcoin Core's bugs. OP_CODESEPARATOR
|
||||||
// is a legacy holdover from a previous, broken design of executing scripts that shipped in Bitcoin 0.1.
|
// is a legacy holdover from a previous, broken design of executing scripts that shipped in Bitcoin 0.1.
|
||||||
@ -80,7 +81,7 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
|
|||||||
// OP_CODESEPARATOR instruction having no purpose as it was only meant to be used internally, not actually
|
// OP_CODESEPARATOR instruction having no purpose as it was only meant to be used internally, not actually
|
||||||
// ever put into scripts. Deleting OP_CODESEPARATOR is a step that should never be required but if we don't
|
// ever put into scripts. Deleting OP_CODESEPARATOR is a step that should never be required but if we don't
|
||||||
// do it, we could split off the main chain.
|
// do it, we could split off the main chain.
|
||||||
val scriptWithOpCodeSeparatorsRemoved : ScriptPubKey = serializeScriptCode(script.asm)
|
val scriptWithOpCodeSeparatorsRemoved : ScriptPubKey = removeOpCodeSeparators(script)
|
||||||
|
|
||||||
val inputToSign = inputSigsRemoved(inputIndex)
|
val inputToSign = inputSigsRemoved(inputIndex)
|
||||||
|
|
||||||
@ -88,17 +89,19 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
|
|||||||
// the signature covers the hash of the prevout transaction which obviously includes the output script
|
// the signature covers the hash of the prevout transaction which obviously includes the output script
|
||||||
// already. Perhaps it felt safer to him in some way, or is another leftover from how the code was written.
|
// already. Perhaps it felt safer to him in some way, or is another leftover from how the code was written.
|
||||||
val inputWithConnectedScript = inputToSign.factory(scriptWithOpCodeSeparatorsRemoved)
|
val inputWithConnectedScript = inputToSign.factory(scriptWithOpCodeSeparatorsRemoved)
|
||||||
|
|
||||||
|
//update the input at index i with inputWithConnectScript
|
||||||
val updatedInputs = for {
|
val updatedInputs = for {
|
||||||
(input,index) <- inputSigsRemoved.zipWithIndex
|
(input,index) <- inputSigsRemoved.zipWithIndex
|
||||||
} yield {
|
} yield {
|
||||||
if (index == inputIndex) inputWithConnectedScript
|
if (index == inputIndex) inputWithConnectedScript
|
||||||
else input
|
else input
|
||||||
}
|
}
|
||||||
//update the input at index i with inputWithConnectScript
|
|
||||||
|
|
||||||
val txWithInputSigsRemoved = spendingTransaction.factory(UpdateTransactionInputs(updatedInputs))
|
val txWithInputSigsRemoved = spendingTransaction.factory(UpdateTransactionInputs(updatedInputs))
|
||||||
//check the hash type
|
|
||||||
|
|
||||||
|
//check the hash type
|
||||||
hashType match {
|
hashType match {
|
||||||
case SIGHASH_NONE =>
|
case SIGHASH_NONE =>
|
||||||
//following this implementation from bitcoinj
|
//following this implementation from bitcoinj
|
||||||
@ -139,7 +142,9 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
|
|||||||
}
|
}
|
||||||
case SIGHASH_ALL =>
|
case SIGHASH_ALL =>
|
||||||
//just need to add the hash type and hash the tx
|
//just need to add the hash type and hash the tx
|
||||||
txWithInputSigsRemoved.bytes ++ List(hashType.byte)
|
//txWithInputSigsRemoved.bytes
|
||||||
|
val sigHashBytes : List[Byte] = List(0x00.toByte, 0x00.toByte, 0x00.toByte, hashType.byte).reverse
|
||||||
|
CryptoUtil.doubleSHA256(txWithInputSigsRemoved.bytes ++ sigHashBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -149,12 +154,9 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
|
|||||||
* format
|
* format
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def removeOpCodeSeparators(script : Seq[ScriptToken]) : ScriptPubKey = {
|
def removeOpCodeSeparators(script : ScriptPubKey) : ScriptPubKey = {
|
||||||
val scriptWithoutOpCodeSeparators : String = script.filterNot(_ == OP_CODESEPARATOR).map(_.hex).mkString
|
val scriptWithoutOpCodeSeparators : Seq[ScriptToken] = script.asm.filterNot(_ == OP_CODESEPARATOR)
|
||||||
val scriptWithoutOpCodeSeparatorSize = addPrecedingZero((scriptWithoutOpCodeSeparators.size / 2).toHexString)
|
ScriptPubKeyFactory.factory(scriptWithoutOpCodeSeparators.flatMap(_.bytes))
|
||||||
val expectedScript : ScriptPubKey = ScriptPubKeyFactory.factory(
|
|
||||||
scriptWithoutOpCodeSeparatorSize + scriptWithoutOpCodeSeparators)
|
|
||||||
expectedScript
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,7 +5,7 @@ import java.util
|
|||||||
import org.bitcoinj.core.{ DumpedPrivateKey}
|
import org.bitcoinj.core.{ DumpedPrivateKey}
|
||||||
import org.bitcoinj.core.Transaction.SigHash
|
import org.bitcoinj.core.Transaction.SigHash
|
||||||
import org.bitcoinj.params.TestNet3Params
|
import org.bitcoinj.params.TestNet3Params
|
||||||
import org.bitcoinj.script.{ScriptChunk, ScriptBuilder}
|
import org.bitcoinj.script.{ScriptOpCodes, ScriptChunk, ScriptBuilder}
|
||||||
import org.scalacoin.protocol.script.{UpdateScriptPubKeyAsm, UpdateScriptPubKeyBytes, ScriptPubKey, ScriptPubKeyFactory}
|
import org.scalacoin.protocol.script.{UpdateScriptPubKeyAsm, UpdateScriptPubKeyBytes, ScriptPubKey, ScriptPubKeyFactory}
|
||||||
import org.scalacoin.protocol.transaction._
|
import org.scalacoin.protocol.transaction._
|
||||||
import org.scalacoin.script.ScriptOperationFactory
|
import org.scalacoin.script.ScriptOperationFactory
|
||||||
@ -13,7 +13,7 @@ import org.scalacoin.script.bitwise.OP_EQUALVERIFY
|
|||||||
import org.scalacoin.script.constant._
|
import org.scalacoin.script.constant._
|
||||||
import org.scalacoin.script.crypto.{OP_CHECKSIG, OP_HASH160, SIGHASH_ALL, OP_CODESEPARATOR}
|
import org.scalacoin.script.crypto.{OP_CHECKSIG, OP_HASH160, SIGHASH_ALL, OP_CODESEPARATOR}
|
||||||
import org.scalacoin.script.stack.OP_DUP
|
import org.scalacoin.script.stack.OP_DUP
|
||||||
import org.scalacoin.util.{ScalacoinUtil, TestUtil}
|
import org.scalacoin.util.{BitcoinjConversions, ScalacoinUtil, TestUtil}
|
||||||
import org.scalatest.{FlatSpec, MustMatchers}
|
import org.scalatest.{FlatSpec, MustMatchers}
|
||||||
import scala.collection.JavaConversions._
|
import scala.collection.JavaConversions._
|
||||||
|
|
||||||
@ -26,24 +26,11 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
|
|||||||
|
|
||||||
"TransactionSignatureSerializer" must "serialize a given script signature without OP_CODESEPARATORS" in {
|
"TransactionSignatureSerializer" must "serialize a given script signature without OP_CODESEPARATORS" in {
|
||||||
val txSerializer = new BaseTransactionSignatureSerializer(TestUtil.transaction)
|
val txSerializer = new BaseTransactionSignatureSerializer(TestUtil.transaction)
|
||||||
val scriptPubKey = TestUtil.scriptPubKey.asm
|
val scriptPubKey = TestUtil.scriptPubKey
|
||||||
val expectedScript = txSerializer.removeOpCodeSeparators(scriptPubKey)
|
val expectedScript = txSerializer.removeOpCodeSeparators(scriptPubKey)
|
||||||
txSerializer.serializeScriptCode(scriptPubKey) must be (expectedScript)
|
txSerializer.serializeScriptCode(scriptPubKey) must be (expectedScript)
|
||||||
}
|
}
|
||||||
|
|
||||||
it must "serialize a given script with only OP_CODESEPARATORs" in {
|
|
||||||
val txSerializer = new BaseTransactionSignatureSerializer(TestUtil.transaction)
|
|
||||||
val scriptPubKey = ScriptPubKeyFactory.factory(UpdateScriptPubKeyAsm(List(OP_CODESEPARATOR)))
|
|
||||||
txSerializer.serializeScriptCode(scriptPubKey.asm).hex must be ("00")
|
|
||||||
}
|
|
||||||
|
|
||||||
it must "serialize a given script with mixed in OP_CODESEPARATORs" in {
|
|
||||||
val txSerializer = new BaseTransactionSignatureSerializer(TestUtil.transaction)
|
|
||||||
val script = List(OP_CODESEPARATOR, OP_1, OP_CODESEPARATOR, OP_0, OP_CODESEPARATOR, OP_2)
|
|
||||||
val scriptPubKey = ScriptPubKeyFactory.factory(UpdateScriptPubKeyAsm(script))
|
|
||||||
txSerializer.serializeScriptCode(scriptPubKey.asm).hex must be ("03510052")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
it must "hash a multisignature SIGHASH_ALL correctly" in {
|
it must "hash a multisignature SIGHASH_ALL correctly" in {
|
||||||
|
|
||||||
@ -53,14 +40,15 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
|
|||||||
val key2 = new DumpedPrivateKey(params, "cTine92s8GLpVqvebi8rYce3FrUYq78ZGQffBYCS1HmDPJdSTxUo").getKey();
|
val key2 = new DumpedPrivateKey(params, "cTine92s8GLpVqvebi8rYce3FrUYq78ZGQffBYCS1HmDPJdSTxUo").getKey();
|
||||||
val key3 = new DumpedPrivateKey(params, "cVHwXSPRZmL9adctwBwmn4oTZdZMbaCsR5XF6VznqMgcvt1FDDxg").getKey();
|
val key3 = new DumpedPrivateKey(params, "cVHwXSPRZmL9adctwBwmn4oTZdZMbaCsR5XF6VznqMgcvt1FDDxg").getKey();
|
||||||
val multiSigScript : org.bitcoinj.script.Script = ScriptBuilder.createMultiSigOutputScript(2, util.Arrays.asList(key1, key2, key3));
|
val multiSigScript : org.bitcoinj.script.Script = ScriptBuilder.createMultiSigOutputScript(2, util.Arrays.asList(key1, key2, key3));
|
||||||
val scriptPubKey = bitcoinjScriptToScriptPubKey(multiSigScript)
|
val scriptPubKey = BitcoinjConversions.toScriptPubKey(multiSigScript)
|
||||||
|
require(scriptPubKey.hex == ScalacoinUtil.encodeHex(multiSigScript.getProgram), "Script pub key hex not the same as multiSigScript hex")
|
||||||
val spendingTx = Transaction.factory(bitcoinjMultiSigTransaction.bitcoinSerialize())
|
val spendingTx = Transaction.factory(bitcoinjMultiSigTransaction.bitcoinSerialize())
|
||||||
|
|
||||||
/*val txSignatureSerializer = new BaseTransactionSignatureSerializer(spendingTx)
|
spendingTx.hex must be (ScalacoinUtil.encodeHex(bitcoinjMultiSigTransaction.bitcoinSerialize()))
|
||||||
val sigBytes = txSignatureSerializer.serialize(0,scriptPubKey,SIGHASH_ALL)
|
|
||||||
|
|
||||||
spendingTx.hex must be (ScalacoinUtil.encodeHex(bitcoinjMultiSigTransaction.bitcoinSerialize()))*/
|
val txSignatureSerializer = new BaseTransactionSignatureSerializer(spendingTx)
|
||||||
|
val sigBytes : Seq[Byte] = txSignatureSerializer.serialize(0,scriptPubKey,SIGHASH_ALL)
|
||||||
|
ScalacoinUtil.encodeHex(sigBytes) must be (createBitcoinjMultiSigScriptHashForSig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -79,8 +67,6 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
|
|||||||
val multisigScript = ScriptBuilder.createMultiSigOutputScript(2, util.Arrays.asList(key1, key2, key3))
|
val multisigScript = ScriptBuilder.createMultiSigOutputScript(2, util.Arrays.asList(key1, key2, key3))
|
||||||
val sighash = spendTx.hashForSignature(0, multisigScript, SigHash.ALL, false)
|
val sighash = spendTx.hashForSignature(0, multisigScript, SigHash.ALL, false)
|
||||||
ScalacoinUtil.encodeHex(sighash.getBytes)
|
ScalacoinUtil.encodeHex(sighash.getBytes)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -99,16 +85,8 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def bitcoinjScriptToScriptPubKey(bitcoinjScript : org.bitcoinj.script.Script) : ScriptPubKey = {
|
|
||||||
|
|
||||||
val parsedScriptTokens : List[ScriptToken] = bitcoinjScript.getChunks.toList.map { chunk =>
|
|
||||||
println("Chunk: " + chunk)
|
|
||||||
if (chunk.isOpCode) ScriptOperationFactory.fromByte(chunk.opcode.toByte).get
|
|
||||||
else new ScriptConstantImpl(chunk.data.toList)
|
|
||||||
}
|
|
||||||
val scriptPubKey = ScriptPubKeyFactory.factory(UpdateScriptPubKeyAsm(parsedScriptTokens))
|
|
||||||
println(scriptPubKey)
|
|
||||||
scriptPubKey
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user