diff --git a/src/main/scala/org/scalacoin/crypto/TransactionSignatureSerializer.scala b/src/main/scala/org/scalacoin/crypto/TransactionSignatureSerializer.scala index 595f16c50a..2d0c84e4c5 100644 --- a/src/main/scala/org/scalacoin/crypto/TransactionSignatureSerializer.scala +++ b/src/main/scala/org/scalacoin/crypto/TransactionSignatureSerializer.scala @@ -34,7 +34,7 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper { * @param script * @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 = ??? @@ -71,7 +71,8 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper { input <- spendingTransaction.inputs } 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 // 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 // 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. - val scriptWithOpCodeSeparatorsRemoved : ScriptPubKey = serializeScriptCode(script.asm) + val scriptWithOpCodeSeparatorsRemoved : ScriptPubKey = removeOpCodeSeparators(script) 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 // 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) + + //update the input at index i with inputWithConnectScript val updatedInputs = for { (input,index) <- inputSigsRemoved.zipWithIndex } yield { if (index == inputIndex) inputWithConnectedScript else input } - //update the input at index i with inputWithConnectScript + val txWithInputSigsRemoved = spendingTransaction.factory(UpdateTransactionInputs(updatedInputs)) - //check the hash type + //check the hash type hashType match { case SIGHASH_NONE => //following this implementation from bitcoinj @@ -139,7 +142,9 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper { } case SIGHASH_ALL => //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 * @return */ - def removeOpCodeSeparators(script : Seq[ScriptToken]) : ScriptPubKey = { - val scriptWithoutOpCodeSeparators : String = script.filterNot(_ == OP_CODESEPARATOR).map(_.hex).mkString - val scriptWithoutOpCodeSeparatorSize = addPrecedingZero((scriptWithoutOpCodeSeparators.size / 2).toHexString) - val expectedScript : ScriptPubKey = ScriptPubKeyFactory.factory( - scriptWithoutOpCodeSeparatorSize + scriptWithoutOpCodeSeparators) - expectedScript + def removeOpCodeSeparators(script : ScriptPubKey) : ScriptPubKey = { + val scriptWithoutOpCodeSeparators : Seq[ScriptToken] = script.asm.filterNot(_ == OP_CODESEPARATOR) + ScriptPubKeyFactory.factory(scriptWithoutOpCodeSeparators.flatMap(_.bytes)) } /** diff --git a/src/test/scala/org/scalacoin/crypto/TransactionSignatureSerializerTest.scala b/src/test/scala/org/scalacoin/crypto/TransactionSignatureSerializerTest.scala index 7d42e8150c..d39dbac0cb 100644 --- a/src/test/scala/org/scalacoin/crypto/TransactionSignatureSerializerTest.scala +++ b/src/test/scala/org/scalacoin/crypto/TransactionSignatureSerializerTest.scala @@ -5,7 +5,7 @@ import java.util import org.bitcoinj.core.{ DumpedPrivateKey} import org.bitcoinj.core.Transaction.SigHash 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.transaction._ 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.crypto.{OP_CHECKSIG, OP_HASH160, SIGHASH_ALL, OP_CODESEPARATOR} 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 scala.collection.JavaConversions._ @@ -26,24 +26,11 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers { "TransactionSignatureSerializer" must "serialize a given script signature without OP_CODESEPARATORS" in { val txSerializer = new BaseTransactionSignatureSerializer(TestUtil.transaction) - val scriptPubKey = TestUtil.scriptPubKey.asm + val scriptPubKey = TestUtil.scriptPubKey val expectedScript = txSerializer.removeOpCodeSeparators(scriptPubKey) 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 { @@ -53,14 +40,15 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers { val key2 = new DumpedPrivateKey(params, "cTine92s8GLpVqvebi8rYce3FrUYq78ZGQffBYCS1HmDPJdSTxUo").getKey(); val key3 = new DumpedPrivateKey(params, "cVHwXSPRZmL9adctwBwmn4oTZdZMbaCsR5XF6VznqMgcvt1FDDxg").getKey(); 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 txSignatureSerializer = new BaseTransactionSignatureSerializer(spendingTx) - val sigBytes = txSignatureSerializer.serialize(0,scriptPubKey,SIGHASH_ALL) + spendingTx.hex must be (ScalacoinUtil.encodeHex(bitcoinjMultiSigTransaction.bitcoinSerialize())) - 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 sighash = spendTx.hashForSignature(0, multisigScript, SigHash.ALL, false) 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 - } + + }