diff --git a/src/main/scala/org/scalacoin/crypto/TransactionSignatureSerializer.scala b/src/main/scala/org/scalacoin/crypto/TransactionSignatureSerializer.scala index 3ee3597696..ca047fdaf8 100644 --- a/src/main/scala/org/scalacoin/crypto/TransactionSignatureSerializer.scala +++ b/src/main/scala/org/scalacoin/crypto/TransactionSignatureSerializer.scala @@ -3,7 +3,6 @@ package org.scalacoin.crypto import org.scalacoin.currency.CurrencyUnits import org.scalacoin.marshallers.RawBitcoinSerializerHelper import org.scalacoin.marshallers.transaction.RawTransactionOutputParser -import org.scalacoin.protocol.{MultiSignature, NonStandard, P2SH, P2PKH} import org.scalacoin.protocol.script._ import org.scalacoin.protocol.transaction._ import org.scalacoin.script.constant.ScriptToken diff --git a/src/main/scala/org/scalacoin/protocol/script/ScriptPubKey.scala b/src/main/scala/org/scalacoin/protocol/script/ScriptPubKey.scala index 08ce2e3ac9..fa7e086506 100644 --- a/src/main/scala/org/scalacoin/protocol/script/ScriptPubKey.scala +++ b/src/main/scala/org/scalacoin/protocol/script/ScriptPubKey.scala @@ -23,7 +23,7 @@ sealed trait ScriptPubKey extends TransactionElement with BitcoinSLogger { */ def asm : Seq[ScriptToken] - /** +/* /** * Returns the script type of this scriptPubKey * @return */ @@ -35,7 +35,7 @@ sealed trait ScriptPubKey extends TransactionElement with BitcoinSLogger { case _ if (asm.last == OP_CHECKMULTISIG) => MultiSignature case _ => NonStandard } - } + }*/ //the addresses that the bitcoins correlated to the output def addresses : Seq[BitcoinAddress] = ??? diff --git a/src/main/scala/org/scalacoin/protocol/transaction/Transaction.scala b/src/main/scala/org/scalacoin/protocol/transaction/Transaction.scala index 2708196274..e161ff1374 100644 --- a/src/main/scala/org/scalacoin/protocol/transaction/Transaction.scala +++ b/src/main/scala/org/scalacoin/protocol/transaction/Transaction.scala @@ -26,6 +26,7 @@ sealed trait Transaction extends TransactionElement { } case object EmptyTransaction extends Transaction { + override def txId = "0000000000000000000000000000000000000000000000000000000000000000" override def version = TransactionConstants.version override def inputs = Seq() override def outputs = Seq() diff --git a/src/main/scala/org/scalacoin/protocol/transaction/TransactionOutput.scala b/src/main/scala/org/scalacoin/protocol/transaction/TransactionOutput.scala index 0385d96078..f7f794506b 100644 --- a/src/main/scala/org/scalacoin/protocol/transaction/TransactionOutput.scala +++ b/src/main/scala/org/scalacoin/protocol/transaction/TransactionOutput.scala @@ -22,7 +22,7 @@ sealed trait TransactionOutput extends TransactionElement { override def hex = RawTransactionOutputParser.write(Seq(this)) } -case object TransactionOutput extends TransactionOutput { +case object EmptyTransactionOutput extends TransactionOutput { override def value = CurrencyUnits.negativeSatoshi override def scriptPubKey = ScriptPubKeyFactory.empty } diff --git a/src/main/scala/org/scalacoin/script/locktime/LockTimeInterpreter.scala b/src/main/scala/org/scalacoin/script/locktime/LockTimeInterpreter.scala index e4225e0b03..23ab205275 100644 --- a/src/main/scala/org/scalacoin/script/locktime/LockTimeInterpreter.scala +++ b/src/main/scala/org/scalacoin/script/locktime/LockTimeInterpreter.scala @@ -1,12 +1,14 @@ package org.scalacoin.script.locktime +import org.scalacoin.protocol.transaction.TransactionConstants import org.scalacoin.script.constant.{ScriptNumberImpl, ScriptNumber} import org.scalacoin.script.{ScriptProgramFactory, ScriptProgramImpl, ScriptProgram} +import org.scalacoin.util.BitcoinSLogger /** * Created by chris on 2/8/16. */ -trait LockTimeInterpreter { +trait LockTimeInterpreter extends BitcoinSLogger { /** @@ -25,14 +27,18 @@ trait LockTimeInterpreter { require(program.script.headOption.isDefined && program.script.head == OP_CHECKLOCKTIMEVERIFY, "Script top must be OP_CHECKLOCKTIMEVERIFY") if (program.stack.size == 0) { + logger.warn("Transaction validation failing in OP_CHECKLOCKTIMEVERIFY because we have no stack items") ScriptProgramFactory.factory(program, program.stack, program.script.tail, false) - } else { + } else if (program.transaction.inputs(program.inputIndex).sequence == TransactionConstants.sequence) { + logger.warn("Transaction validation failing in OP_CHECKLOCKTIMEVERIFY because the sequence number is 0xffffffff") + ScriptProgramFactory.factory(program, program.stack, program.script.tail, false) + } + else { val isValid = program.stack.head match { case s : ScriptNumber if (s < ScriptNumberImpl(0)) => false case s : ScriptNumber if (s > ScriptNumberImpl(500000000) && program.transaction.lockTime < 500000000) => false case s : ScriptNumber if (s < ScriptNumberImpl(500000000) && program.transaction.lockTime > 500000000) => false - case s if (program.transaction.inputs.map(_.sequence == 0xffffffff).exists(_ == true)) => false - case _ => true + case _ => false } ScriptProgramFactory.factory(program,program.stack, program.script.tail, isValid) } diff --git a/src/test/scala/org/scalacoin/marshallers/transaction/RawTransactionOutputParserTest.scala b/src/test/scala/org/scalacoin/marshallers/transaction/RawTransactionOutputParserTest.scala index c4e8ad50f6..5cf25e0aec 100644 --- a/src/test/scala/org/scalacoin/marshallers/transaction/RawTransactionOutputParserTest.scala +++ b/src/test/scala/org/scalacoin/marshallers/transaction/RawTransactionOutputParserTest.scala @@ -1,7 +1,6 @@ package org.scalacoin.marshallers.transaction import org.scalacoin.currency.{Satoshis, CurrencyUnits, Bitcoins} -import org.scalacoin.protocol.{P2PKH, P2SH} import org.scalacoin.protocol.transaction.TransactionOutput import org.scalacoin.script.bitwise.OP_EQUAL import org.scalacoin.script.constant.{BytesToPushOntoStackImpl, ScriptConstantImpl} @@ -26,8 +25,6 @@ class RawTransactionOutputParserTest extends FlatSpec with MustMatchers with Raw secondOutput.value must be (CurrencyUnits.toSatoshis(Bitcoins(0.02981145))) firstOutput.scriptPubKey.asm must be (Seq(OP_HASH160, BytesToPushOntoStackImpl(20),ScriptConstantImpl("eda8ae08b5c9f973f49543e90a7c292367b3337c"), OP_EQUAL)) secondOutput.scriptPubKey.asm must be (Seq(OP_HASH160,BytesToPushOntoStackImpl(20), ScriptConstantImpl("be2319b9060429692ebeffaa3be38497dc5380c8"), OP_EQUAL)) - firstOutput.scriptPubKey.scriptType must be (P2SH) - secondOutput.scriptPubKey.scriptType must be (P2SH) } it must "seralialize a transaction output" in { @@ -54,7 +51,5 @@ class RawTransactionOutputParserTest extends FlatSpec with MustMatchers with Raw val rawTwoOutputs = "026c405d05000000001976a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac809698000000000017a914af575bd77c5ce7eba3bd9ce6f89774713ae62c7987" val outputs = RawTransactionOutputParser.read(rawTwoOutputs) outputs.size must be (2) - outputs.head.scriptPubKey.scriptType must be (P2PKH) - outputs(1).scriptPubKey.scriptType must be (P2SH) } } diff --git a/src/test/scala/org/scalacoin/protocol/script/ScriptPubKeyTest.scala b/src/test/scala/org/scalacoin/protocol/script/ScriptPubKeyTest.scala index 43182cd262..7447215c58 100644 --- a/src/test/scala/org/scalacoin/protocol/script/ScriptPubKeyTest.scala +++ b/src/test/scala/org/scalacoin/protocol/script/ScriptPubKeyTest.scala @@ -1,7 +1,6 @@ package org.scalacoin.protocol.script import org.scalacoin.crypto.ECFactory -import org.scalacoin.protocol.{MultiSignature, P2SH, P2PKH} import org.scalacoin.script.bitwise.OP_EQUALVERIFY import org.scalacoin.script.constant.{ScriptConstantImpl, BytesToPushOntoStackImpl, ScriptToken} import org.scalacoin.script.crypto.{OP_CHECKSIG, OP_HASH160, OP_CODESEPARATOR} @@ -24,25 +23,4 @@ class ScriptPubKeyTest extends FlatSpec with MustMatchers { scriptPubKey.asm must be (expectedAsm) } - it must "derive a P2PKH script type from a scriptPubKey" in { - scriptPubKey.scriptType must be (P2PKH) - } - - it must "derive a P2SH script type for a scriptPubKey" in { - - TestUtil.p2shScriptPubKey.scriptType must be (P2SH) - } - - - - it must "derive a multisignature script type for a scriptPubKey" in { - val multiSigRawScriptPubKey = "5221025878e270211662a27181cf" + - "4d6ad4d2cf0e69a98a3815c086f587c7e9388d87182103fc85980e3fac1f3d" + - "8a5c3223c3ef5bffc1bd42d2cc42add8c3899cc66e7f1906210215b5bd0508" + - "69166a70a7341b4f216e268b7c6c7504576dcea2cce7d11cc9a35f53ae" - val multiSigScriptPubKey = ScriptPubKeyFactory.fromHex(multiSigRawScriptPubKey) - - multiSigScriptPubKey.scriptType must be (MultiSignature) - } - } diff --git a/src/test/scala/org/scalacoin/protocol/transaction/TransactionInputTest.scala b/src/test/scala/org/scalacoin/protocol/transaction/TransactionInputTest.scala new file mode 100644 index 0000000000..77076dcb3d --- /dev/null +++ b/src/test/scala/org/scalacoin/protocol/transaction/TransactionInputTest.scala @@ -0,0 +1,19 @@ +package org.scalacoin.protocol.transaction + +import org.scalacoin.protocol.script.EmptyScriptSignature +import org.scalatest.{FlatSpec, MustMatchers} + +/** + * Created by chris on 3/30/16. + */ +class TransactionInputTest extends FlatSpec with MustMatchers { + + + "TransactionInput" must "define an empty transaction input" in { + EmptyTransactionInput.previousOutput must be (EmptyTransactionOutPoint) + EmptyTransactionInput.scriptSignature must be (EmptyScriptSignature) + EmptyTransactionInput.scriptSigCompactSizeUInt.num must be (0) + EmptyTransactionInput.scriptSigCompactSizeUInt.size must be (1) + EmptyTransactionInput.sequence must be (TransactionConstants.sequence) + } +} diff --git a/src/test/scala/org/scalacoin/protocol/transaction/TransactionOutPointTest.scala b/src/test/scala/org/scalacoin/protocol/transaction/TransactionOutPointTest.scala new file mode 100644 index 0000000000..c7d6ea67cb --- /dev/null +++ b/src/test/scala/org/scalacoin/protocol/transaction/TransactionOutPointTest.scala @@ -0,0 +1,13 @@ +package org.scalacoin.protocol.transaction + +import org.scalatest.{FlatSpec, MustMatchers} + +/** + * Created by chris on 3/30/16. + */ +class TransactionOutPointTest extends FlatSpec with MustMatchers { + "TransactionOutPoint" must "define an empty transaction outpoint" in { + EmptyTransactionOutPoint.txId must be ("") + EmptyTransactionOutPoint.vout must be (-1) + } +} diff --git a/src/test/scala/org/scalacoin/protocol/transaction/TransactionOutputTest.scala b/src/test/scala/org/scalacoin/protocol/transaction/TransactionOutputTest.scala new file mode 100644 index 0000000000..a7eec273ad --- /dev/null +++ b/src/test/scala/org/scalacoin/protocol/transaction/TransactionOutputTest.scala @@ -0,0 +1,16 @@ +package org.scalacoin.protocol.transaction + +import org.scalacoin.currency.CurrencyUnits +import org.scalacoin.protocol.script.EmptyScriptPubKey +import org.scalatest.{FlatSpec, MustMatchers} + +/** + * Created by chris on 3/30/16. + */ +class TransactionOutputTest extends FlatSpec with MustMatchers { + + "TransactionOutput" must "define an empty transaction output" in { + EmptyTransactionOutput.scriptPubKey must be (EmptyScriptPubKey) + EmptyTransactionOutput.value must be (CurrencyUnits.negativeSatoshi) + } +} diff --git a/src/test/scala/org/scalacoin/protocol/transaction/TransactionTest.scala b/src/test/scala/org/scalacoin/protocol/transaction/TransactionTest.scala index 695b483f31..e7dd4806be 100644 --- a/src/test/scala/org/scalacoin/protocol/transaction/TransactionTest.scala +++ b/src/test/scala/org/scalacoin/protocol/transaction/TransactionTest.scala @@ -16,4 +16,11 @@ class TransactionTest extends FlatSpec with MustMatchers { tx.txId must be ("cddda897b0e9322937ee1f4fd5d6147d60f04a0f4d3b461e4f87066ac3918f2a") } + + it must "have an empty transaction with the correct fields" in { + EmptyTransaction.inputs.isEmpty must be (true) + EmptyTransaction.outputs.isEmpty must be (true) + EmptyTransaction.lockTime must be (TransactionConstants.lockTime) + EmptyTransaction.txId must be ("0000000000000000000000000000000000000000000000000000000000000000") + } } diff --git a/src/test/scala/org/scalacoin/script/locktime/LockTimeInterpreterTest.scala b/src/test/scala/org/scalacoin/script/locktime/LockTimeInterpreterTest.scala new file mode 100644 index 0000000000..27031f9989 --- /dev/null +++ b/src/test/scala/org/scalacoin/script/locktime/LockTimeInterpreterTest.scala @@ -0,0 +1,28 @@ +package org.scalacoin.script.locktime + +import org.scalacoin.script.ScriptProgramFactory +import org.scalacoin.script.constant.OP_0 +import org.scalacoin.util.TestUtil +import org.scalatest.{MustMatchers, FlatSpec} + +/** + * Created by chris on 3/30/16. + */ +class LockTimeInterpreterTest extends FlatSpec with MustMatchers with LockTimeInterpreter { + + "LockTimeInterpreter" must "mark the transaction invalid if the stack is empty" in { + val stack = Seq() + val script = Seq(OP_CHECKLOCKTIMEVERIFY) + val program = ScriptProgramFactory.factory(TestUtil.testProgram,stack,script) + val newProgram = opCheckLockTimeVerify(program) + newProgram.isValid must be (false) + } + + it must "mark the transaction invalid if the transaction's sequence number is set to the max" in { + val stack = Seq(OP_0) + val script = Seq(OP_CHECKLOCKTIMEVERIFY) + val program = ScriptProgramFactory.factory(TestUtil.testProgram,stack,script) + val newProgram = opCheckLockTimeVerify(program) + newProgram.isValid must be (false) + } +}