mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-23 14:50:42 +01:00
Removing inheritance for ScriptPubKeyFactory from ScriptSignature - these are unique enough to not warrant inheritance
This commit is contained in:
parent
fa31877758
commit
4b9a203786
13 changed files with 105 additions and 35 deletions
|
@ -1,9 +1,33 @@
|
|||
package org.scalacoin.crypto
|
||||
|
||||
import org.scalacoin.protocol.script.ScriptPubKey
|
||||
import org.scalacoin.protocol.transaction.{Transaction, TransactionInput}
|
||||
import org.scalacoin.script.crypto.HashType
|
||||
|
||||
/**
|
||||
* Created by chris on 2/16/16.
|
||||
*/
|
||||
trait TransactionSignatureChecker extends BaseSignatureChecker {
|
||||
trait TransactionSignatureChecker {
|
||||
|
||||
|
||||
/**
|
||||
* Checks the signature of a scriptSig in the spending transaction against the
|
||||
* given scriptPubKey
|
||||
* @param spendingTransaction
|
||||
* @param inputIndex
|
||||
* @param scriptPubKey
|
||||
* @param signature
|
||||
* @param pubKey
|
||||
* @param hashType
|
||||
* @return
|
||||
*/
|
||||
def checkSignature(spendingTransaction : Transaction, inputIndex : Int, scriptPubKey : ScriptPubKey,
|
||||
signature : ECDigitalSignature, pubKey: ECPublicKey, hashType : HashType) : Boolean = {
|
||||
val hashForSignature = TransactionSignatureSerializer.hashForSignature(spendingTransaction,inputIndex,scriptPubKey,hashType)
|
||||
val isValid = pubKey.verify(hashForSignature,signature)
|
||||
isValid
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object TransactionSignatureChecker extends TransactionSignatureChecker
|
||||
|
|
|
@ -3,7 +3,7 @@ package org.scalacoin.crypto
|
|||
import org.scalacoin.currency.CurrencyUnits
|
||||
import org.scalacoin.marshallers.RawBitcoinSerializerHelper
|
||||
import org.scalacoin.marshallers.transaction.RawTransactionOutputParser
|
||||
import org.scalacoin.protocol.script.{ScriptSignatureFactory, ScriptSignatureImpl, ScriptPubKeyFactory, ScriptPubKey}
|
||||
import org.scalacoin.protocol.script._
|
||||
import org.scalacoin.protocol.transaction._
|
||||
import org.scalacoin.script.constant.ScriptToken
|
||||
import org.scalacoin.script.crypto._
|
||||
|
@ -168,7 +168,7 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
|
|||
updatedTx
|
||||
}
|
||||
/**
|
||||
* Removes OP_CODESEPARATOR operations then returns the script in hex
|
||||
* Removes OP_CODESEPARATOR operations then returns the script
|
||||
* format
|
||||
* @return
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.scalacoin.protocol.script
|
||||
|
||||
import org.scalacoin.marshallers.transaction.TransactionElement
|
||||
import org.scalacoin.protocol._
|
||||
import org.scalacoin.script.bitwise.{OP_EQUAL, OP_EQUALVERIFY}
|
||||
import org.scalacoin.script.constant.{BytesToPushOntoStackImpl, ScriptConstantImpl, ScriptToken}
|
||||
|
@ -9,7 +10,15 @@ import org.scalacoin.script.stack.OP_DUP
|
|||
/**
|
||||
* Created by chris on 12/26/15.
|
||||
*/
|
||||
trait ScriptPubKey extends ScriptSignature {
|
||||
sealed trait ScriptPubKey extends TransactionElement {
|
||||
|
||||
/**
|
||||
* Representation of a scriptSignature in a parsed assembly format
|
||||
* this data structure can be run through the script interpreter to
|
||||
* see if a script evaluates to true
|
||||
* @return
|
||||
*/
|
||||
def asm : Seq[ScriptToken]
|
||||
|
||||
|
||||
def reqSigs : Option[Int] = {
|
||||
|
@ -33,4 +42,5 @@ trait ScriptPubKey extends ScriptSignature {
|
|||
|
||||
}
|
||||
|
||||
|
||||
case class ScriptPubKeyImpl(asm : Seq[ScriptToken], hex : String, addresses : Seq[BitcoinAddress]) extends ScriptPubKey
|
||||
|
|
|
@ -11,7 +11,7 @@ import org.slf4j.LoggerFactory
|
|||
/**
|
||||
* Created by chris on 12/26/15.
|
||||
*/
|
||||
trait ScriptSignature extends TransactionElement {
|
||||
sealed trait ScriptSignature extends TransactionElement {
|
||||
|
||||
private def logger = LoggerFactory.getLogger(this.getClass())
|
||||
|
||||
|
@ -47,23 +47,15 @@ trait ScriptSignature extends TransactionElement {
|
|||
}
|
||||
|
||||
/**
|
||||
* Derives the hash type for a given scriptSig
|
||||
* @param scriptSig
|
||||
* Derives the hash type for a given digitalSignature
|
||||
* @param digitalSignature
|
||||
* @return
|
||||
*/
|
||||
def hashType(scriptSig : Seq[Byte]) : HashType = {
|
||||
require(HashTypeFactory.fromByte(scriptSig.last).isDefined,
|
||||
"Hash type could not be read for this scriptSig: " + BitcoinSUtil.encodeHex(scriptSig))
|
||||
HashTypeFactory.fromByte(scriptSig.last).get
|
||||
def hashType(digitalSignature: ECDigitalSignature) = {
|
||||
require(HashTypeFactory.fromByte(digitalSignature.bytes.last).isDefined,
|
||||
"Hash type could not be read for this scriptSig: " + digitalSignature.hex)
|
||||
HashTypeFactory.fromByte(digitalSignature.bytes.last).get
|
||||
}
|
||||
|
||||
/**
|
||||
* Derives the hash type for a give scriptSig
|
||||
* @param scriptSigHex
|
||||
* @return
|
||||
*/
|
||||
def hashType(scriptSigHex : String) : HashType = hashType(BitcoinSUtil.decodeHex(scriptSigHex))
|
||||
|
||||
}
|
||||
|
||||
case class ScriptSignatureImpl(asm : Seq[ScriptToken], hex : String) extends ScriptSignature
|
|
@ -8,7 +8,7 @@ import org.scalacoin.util.{BitcoinSUtil, CryptoUtil}
|
|||
*/
|
||||
|
||||
|
||||
trait Transaction extends TransactionElement with TransactionFactory {
|
||||
sealed trait Transaction extends TransactionElement with TransactionFactory {
|
||||
def txId : String = BitcoinSUtil.encodeHex(CryptoUtil.doubleSHA256(hex).reverse)
|
||||
def version : Long
|
||||
def inputs : Seq[TransactionInput]
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.scalacoin.util.{BitcoinSUtil, ScalacoinUtil}
|
|||
/**
|
||||
* Created by chris on 12/26/15.
|
||||
*/
|
||||
trait TransactionInput extends TransactionElement with TransactionInputFactory {
|
||||
sealed trait TransactionInput extends TransactionElement with TransactionInputFactory {
|
||||
|
||||
def previousOutput : TransactionOutPoint
|
||||
def scriptSignature : ScriptSignature
|
||||
|
|
|
@ -5,7 +5,7 @@ import org.scalacoin.marshallers.transaction.{RawTransactionOutPointParser, Tran
|
|||
/**
|
||||
* Created by chris on 12/26/15.
|
||||
*/
|
||||
trait TransactionOutPoint extends TransactionElement with TransactionOutPointFactory {
|
||||
sealed trait TransactionOutPoint extends TransactionElement with TransactionOutPointFactory {
|
||||
def txId : String
|
||||
def vout : Int
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.scalacoin.protocol.script.{ScriptPubKeyFactory, ScriptPubKey}
|
|||
/**
|
||||
* Created by chris on 12/26/15.
|
||||
*/
|
||||
trait TransactionOutput extends TransactionElement with TransactionOutputFactory {
|
||||
sealed trait TransactionOutput extends TransactionElement with TransactionOutputFactory {
|
||||
|
||||
def value : CurrencyUnit
|
||||
def n : Int
|
||||
|
|
|
@ -19,7 +19,7 @@ class ECPublicKeyTest extends FlatSpec with MustMatchers {
|
|||
isValid must be (true)
|
||||
}
|
||||
|
||||
it must "fail to validate a piece of data if the wrong public key is given" in {
|
||||
it must "fail to verify a piece of data if the wrong public key is given" in {
|
||||
val privateKeyHex = "180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19"
|
||||
val key: ECPrivateKey = ECFactory.privateKey(privateKeyHex)
|
||||
val signature: ECDigitalSignature = key.sign(Sha256Hash.ZERO_HASH.getBytes.toSeq)
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package org.scalacoin.crypto
|
||||
|
||||
import org.scalacoin.protocol.script.ScriptSignature
|
||||
import org.scalacoin.protocol.transaction.{TransactionInput, Transaction, TransactionOutput}
|
||||
import org.scalacoin.script.crypto.SIGHASH_ALL
|
||||
import org.scalacoin.util.{TransactionTestUtil, TestUtil}
|
||||
import org.scalatest.{FlatSpec, MustMatchers}
|
||||
|
||||
/**
|
||||
* Created by chris on 2/29/16.
|
||||
*/
|
||||
class TransactionSignatureCheckerTest extends FlatSpec with MustMatchers {
|
||||
|
||||
"TransactionSignatureChecker" must "check to see if an input correctly spends a scriptPubKey" in {
|
||||
val (spendingTx,spendingInput,creditingOutput) : (Transaction,TransactionInput,TransactionOutput) =
|
||||
TransactionTestUtil.transactionWithSpendingInputAndCreditingOutput
|
||||
val scriptSig : ScriptSignature = spendingInput.scriptSignature
|
||||
val pubKey : ECPublicKey = ECFactory.publicKey(scriptSig.asm.last.bytes)
|
||||
require("30450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01" == scriptSig.signatures.head.hex)
|
||||
require("0241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353" == pubKey.hex)
|
||||
val hashType = scriptSig.hashType(scriptSig.signatures.head)
|
||||
require(hashType == SIGHASH_ALL)
|
||||
TransactionSignatureChecker.checkSignature(spendingTx,0,creditingOutput.scriptPubKey,
|
||||
scriptSig.signatures.head,pubKey,hashType) must be (true)
|
||||
}
|
||||
}
|
|
@ -233,14 +233,16 @@ class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
|
|||
private def createBitcoinjMultiSigScriptHashForSig(hashType : HashType) : String = {
|
||||
val spendTx = bitcoinjMultiSigTransaction
|
||||
|
||||
val sighash : String = hashType match {
|
||||
case SIGHASH_ALL => BitcoinSUtil.encodeHex(spendTx.hashForSignature(0, multiSigScript, SigHash.ALL, false).getBytes)
|
||||
case SIGHASH_SINGLE => BitcoinSUtil.encodeHex(spendTx.hashForSignature(0,multiSigScript,SigHash.SINGLE, false).getBytes)
|
||||
case SIGHASH_NONE => BitcoinSUtil.encodeHex(spendTx.hashForSignature(0,multiSigScript,SigHash.NONE, false).getBytes)
|
||||
case SIGHASH_ANYONECANPAY => BitcoinSUtil.encodeHex(spendTx.hashForSignature(0,multiSigScript.getProgram,0x80.toByte).getBytes)
|
||||
|
||||
val sighash : Seq[Byte] = hashType match {
|
||||
case SIGHASH_ALL => spendTx.hashForSignature(0, multiSigScript, SigHash.ALL, false).getBytes
|
||||
case SIGHASH_SINGLE => spendTx.hashForSignature(0,multiSigScript,SigHash.SINGLE, false).getBytes
|
||||
case SIGHASH_NONE => spendTx.hashForSignature(0,multiSigScript,SigHash.NONE, false).getBytes
|
||||
case SIGHASH_ANYONECANPAY => spendTx.hashForSignature(0,multiSigScript.getProgram,0x80.toByte).getBytes
|
||||
case SIGHASH_ALL_ANYONECANPAY => spendTx.hashForSignature(0,multiSigScript.getProgram,SIGHASH_ALL_ANYONECANPAY.byte).getBytes
|
||||
case SIGHASH_SINGLE_ANYONECANPAY => spendTx.hashForSignature(0,multiSigScript.getProgram,SIGHASH_SINGLE_ANYONECANPAY.byte).getBytes
|
||||
case SIGHASH_NONE_ANYONECANPAY => spendTx.hashForSignature(0,multiSigScript.getProgram,SIGHASH_NONE_ANYONECANPAY.byte).getBytes
|
||||
}
|
||||
sighash
|
||||
BitcoinSUtil.encodeHex(sighash)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ class ScriptSignatureTest extends FlatSpec with MustMatchers {
|
|||
}
|
||||
|
||||
it must "derive the signature hash type from the signature" in {
|
||||
TestUtil.scriptSig.hashType(TestUtil.scriptSig.signatures.head.bytes) must be (SIGHASH_ALL)
|
||||
TestUtil.scriptSig.hashType(TestUtil.scriptSig.signatures.head) must be (SIGHASH_ALL)
|
||||
}
|
||||
|
||||
|
||||
|
@ -48,19 +48,19 @@ class ScriptSignatureTest extends FlatSpec with MustMatchers {
|
|||
))
|
||||
}
|
||||
it must "find the hash type for a p2sh script signature" in {
|
||||
TestUtil.p2shInputScript.hashType(TestUtil.p2shInputScript2Of3.signatures.head.hex) must be (SIGHASH_ALL)
|
||||
TestUtil.p2shInputScript.hashType(TestUtil.p2shInputScript2Of3.signatures.head) must be (SIGHASH_ALL)
|
||||
}
|
||||
|
||||
it must "find the digital signature and hash type for a SIGHASH_SINGLE" in {
|
||||
TestUtil.p2shInputScriptSigHashSingle.signatures.head.hex must be ("3045022100dfcfafcea73d83e1c54d444a19fb30d17317f922c19e2ff92dcda65ad09cba24022001e7a805c5672c49b222c5f2f1e67bb01f87215fb69df184e7c16f66c1f87c2903")
|
||||
TestUtil.p2shInputScriptSigHashSingle.hashType(TestUtil.p2shInputScriptSigHashSingle.signatures.head.hex) must be (SIGHASH_SINGLE)
|
||||
TestUtil.p2shInputScriptSigHashSingle.hashType(TestUtil.p2shInputScriptSigHashSingle.signatures.head) must be (SIGHASH_SINGLE)
|
||||
}
|
||||
|
||||
it must "the hash type for the weird occurrence of hash type being 0 on the blockchain" in {
|
||||
//from this tx https://btc.blockr.io/api/v1/tx/raw/c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73
|
||||
val hex = "493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5"
|
||||
val scriptSig : ScriptSignature = RawScriptSignatureParser.read(hex)
|
||||
scriptSig.hashType(scriptSig.signatures.head.bytes) must be (SIGHASH_ALL)
|
||||
scriptSig.hashType(scriptSig.signatures.head) must be (SIGHASH_ALL)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,4 +43,20 @@ trait TransactionTestUtil {
|
|||
|
||||
TransactionImpl(TransactionConstants.version,Seq(input),Seq(output),TransactionConstants.lockTime)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a transaction and its crediting output
|
||||
* @return
|
||||
*/
|
||||
def transactionWithSpendingInputAndCreditingOutput : (Transaction, TransactionInput, TransactionOutput) = {
|
||||
val spendingTx = TestUtil.simpleTransaction
|
||||
val creditingTx = TestUtil.parentSimpleTransaction
|
||||
val creditingOutput = TestUtil.parentSimpleTransaction.outputs(creditingTx.inputs.head.previousOutput.vout)
|
||||
//make sure the outpoint index and the outpoint txid are correct
|
||||
require(spendingTx.inputs.head.previousOutput.txId == creditingTx.txId)
|
||||
(spendingTx,spendingTx.inputs.head, creditingOutput)
|
||||
}
|
||||
}
|
||||
|
||||
object TransactionTestUtil extends TransactionTestUtil
|
||||
|
|
Loading…
Add table
Reference in a new issue