mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-03 10:46:42 +01:00
Increase some Test Coverage (#866)
* Added ScriptTypeTest * Added ScriptSignature coverage * Added Signer test coverage * Added test coverage for UTXOSpendingInfo * Responded to code review
This commit is contained in:
parent
b80a46ca9a
commit
fad72c66d5
8 changed files with 185 additions and 67 deletions
|
@ -0,0 +1,51 @@
|
|||
package org.bitcoins.core.protocol.script
|
||||
|
||||
import org.bitcoins.core.script.constant.{OP_FALSE, OP_TRUE}
|
||||
import org.bitcoins.testkit.core.gen.{NumberGenerator, ScriptGenerators}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
|
||||
class ConditionalScriptSignatureTest extends BitcoinSUnitTest {
|
||||
behavior of "ConditionalScriptSignature"
|
||||
|
||||
implicit override val generatorDrivenConfig: PropertyCheckConfiguration = {
|
||||
generatorDrivenConfigNewCode
|
||||
}
|
||||
|
||||
it should "correctly read true and false" in {
|
||||
val trueScriptSig = ConditionalScriptSignature.fromAsm(Vector(OP_TRUE))
|
||||
val falseScriptSig = ConditionalScriptSignature.fromAsm(Vector(OP_FALSE))
|
||||
|
||||
assert(trueScriptSig.isTrue)
|
||||
assert(!trueScriptSig.isFalse)
|
||||
assert(!falseScriptSig.isTrue)
|
||||
assert(falseScriptSig.isFalse)
|
||||
assert(trueScriptSig.nestedScriptSig == EmptyScriptSignature)
|
||||
assert(falseScriptSig.nestedScriptSig == EmptyScriptSignature)
|
||||
}
|
||||
|
||||
it should "have serialization symmetry" in {
|
||||
forAll(ScriptGenerators.conditionalScriptSignature) {
|
||||
conditionalScriptSignature =>
|
||||
assert(
|
||||
ConditionalScriptSignature(conditionalScriptSignature.bytes) == conditionalScriptSignature)
|
||||
}
|
||||
}
|
||||
|
||||
it should "have agreement with nesting ScriptSignatures" in {
|
||||
forAll(ScriptGenerators.scriptSignature, NumberGenerator.bool) {
|
||||
case (scriptSig, condition) =>
|
||||
val conditionalScriptSig =
|
||||
ConditionalScriptSignature(scriptSig, condition)
|
||||
|
||||
assert(conditionalScriptSig.nestedScriptSig == scriptSig)
|
||||
}
|
||||
}
|
||||
|
||||
it should "have agreement with nested signatures" in {
|
||||
forAll(ScriptGenerators.conditionalScriptSignature) {
|
||||
conditionalScriptSignature =>
|
||||
assert(
|
||||
conditionalScriptSignature.signatures == conditionalScriptSignature.nestedScriptSig.signatures)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package org.bitcoins.core.protocol.script
|
||||
|
||||
import org.bitcoins.testkit.core.gen.ScriptGenerators
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
|
||||
class LockTimeScriptSignatureTest extends BitcoinSUnitTest {
|
||||
behavior of "LockTimeScriptSignature"
|
||||
|
||||
implicit override val generatorDrivenConfig: PropertyCheckConfiguration = {
|
||||
generatorDrivenConfigNewCode
|
||||
}
|
||||
|
||||
it should "have agreement with nesting ScriptSignatures" in {
|
||||
forAll(ScriptGenerators.scriptSignature) { scriptSig =>
|
||||
val csvScriptSig = CSVScriptSignature(scriptSig)
|
||||
val cltvScriptSig = CLTVScriptSignature(scriptSig)
|
||||
|
||||
assert(csvScriptSig.scriptSig == scriptSig)
|
||||
assert(cltvScriptSig.scriptSig == scriptSig)
|
||||
}
|
||||
}
|
||||
|
||||
it should "have agreement with nested signatures" in {
|
||||
forAll(ScriptGenerators.lockTimeScriptSig) { lockTimeScriptSignature =>
|
||||
assert(
|
||||
lockTimeScriptSignature.signatures == lockTimeScriptSignature.scriptSig.signatures)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,4 +15,10 @@ class MultiSignatureScriptSignatureTest extends BitcoinSUnitTest {
|
|||
scriptSig.signatures.size must be(2)
|
||||
}
|
||||
|
||||
it must "Fail validation if asm is empty" in {
|
||||
assert(
|
||||
!MultiSignatureScriptSignature.isMultiSignatureScriptSignature(
|
||||
Vector.empty))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package org.bitcoins.core.script
|
||||
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
|
||||
class ScriptTypeTest extends BitcoinSUnitTest {
|
||||
behavior of "ScriptType"
|
||||
|
||||
it must "have serialization symmetry" in {
|
||||
ScriptType.all.foreach { scriptType =>
|
||||
val newScriptType = ScriptType.fromString(scriptType.toString)
|
||||
|
||||
assert(newScriptType.contains(scriptType))
|
||||
}
|
||||
}
|
||||
|
||||
it must "fail when nonsense ScriptType is used" in {
|
||||
val lyrics = "Never gonna give you up, never gonna let you down"
|
||||
|
||||
assert(ScriptType.fromString(lyrics).isEmpty)
|
||||
assertThrows[IllegalArgumentException](ScriptType.fromStringExn(lyrics))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package org.bitcoins.core.wallet.signer
|
||||
|
||||
import org.bitcoins.core.protocol.script.WitnessScriptPubKey
|
||||
import org.bitcoins.core.wallet.utxo.{
|
||||
P2SHSpendingInfo,
|
||||
P2WPKHV0SpendingInfo,
|
||||
P2WSHV0SpendingInfo,
|
||||
UnassignedSegwitNativeUTXOSpendingInfo
|
||||
}
|
||||
import org.bitcoins.testkit.core.gen.{CreditingTxGen, TransactionGenerators}
|
||||
import org.bitcoins.testkit.util.{BitcoinSAsyncTest, BitcoinSUnitTest}
|
||||
|
||||
import scala.concurrent.ExecutionContext
|
||||
|
||||
class SignerTest extends BitcoinSAsyncTest {
|
||||
|
||||
implicit val ec: ExecutionContext = ExecutionContext.global
|
||||
|
||||
behavior of "Signer"
|
||||
|
||||
it should "fail to sign a UnassignedSegwit UTXO" in {
|
||||
val p2wpkh = CreditingTxGen.p2wpkhOutput.sample.get
|
||||
val tx = TransactionGenerators.baseTransaction.sample.get
|
||||
val spendingInfo = UnassignedSegwitNativeUTXOSpendingInfo(
|
||||
p2wpkh.outPoint,
|
||||
p2wpkh.amount,
|
||||
p2wpkh.scriptPubKey.asInstanceOf[WitnessScriptPubKey],
|
||||
p2wpkh.signers,
|
||||
p2wpkh.hashType,
|
||||
p2wpkh.scriptWitnessOpt.get,
|
||||
p2wpkh.conditionalPath
|
||||
)
|
||||
assertThrows[UnsupportedOperationException](
|
||||
BitcoinSigner.sign(spendingInfo, tx, isDummySignature = false))
|
||||
}
|
||||
|
||||
it should "fail to sign a P2SH UTXO" in {
|
||||
val p2sh = CreditingTxGen.p2shOutput.sample.get
|
||||
val tx = TransactionGenerators.baseTransaction.sample.get
|
||||
assertThrows[IllegalArgumentException](
|
||||
BitcoinSigner.sign(p2sh, tx, isDummySignature = false))
|
||||
}
|
||||
|
||||
it should "fail if there are inconsistent P2WPKH spending infos" in {
|
||||
val dumbSpendingInfo = CreditingTxGen.output.sample.get
|
||||
val p2wpkh =
|
||||
CreditingTxGen.p2wpkhOutput.sample.get.asInstanceOf[P2WPKHV0SpendingInfo]
|
||||
val tx = TransactionGenerators.baseTransaction.sample.get
|
||||
recoverToSucceededIf[IllegalArgumentException] {
|
||||
P2WPKHSigner.sign(dumbSpendingInfo, tx, isDummySignature = false, p2wpkh)
|
||||
}
|
||||
}
|
||||
|
||||
it should "fail if there are inconsistent P2WSH spending infos" in {
|
||||
val dumbSpendingInfo = CreditingTxGen.output.sample.get
|
||||
val p2wsh =
|
||||
CreditingTxGen.p2wshOutput.sample.get.asInstanceOf[P2WSHV0SpendingInfo]
|
||||
val tx = TransactionGenerators.baseTransaction.sample.get
|
||||
recoverToSucceededIf[IllegalArgumentException] {
|
||||
P2WSHSigner.sign(dumbSpendingInfo, tx, isDummySignature = false, p2wsh)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -177,15 +177,6 @@ sealed trait P2SHScriptSignature extends ScriptSignature {
|
|||
sigs.map(s => ECDigitalSignature(s.hex))
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the given asm into two parts
|
||||
* the first part is the digital signatures
|
||||
* the second part is the redeem script
|
||||
*/
|
||||
def splitAtRedeemScript: (Seq[ScriptToken], Seq[ScriptToken]) = {
|
||||
(scriptSignatureNoRedeemScript.asm, redeemScript.asm)
|
||||
}
|
||||
|
||||
override def toString = "P2SHScriptSignature(" + hex + ")"
|
||||
}
|
||||
|
||||
|
@ -225,10 +216,8 @@ object P2SHScriptSignature extends ScriptFactory[P2SHScriptSignature] {
|
|||
}
|
||||
|
||||
/** Tests if the given asm tokens are a [[P2SHScriptSignature]] */
|
||||
def isP2SHScriptSig(asm: Seq[ScriptToken]): Boolean = asm match {
|
||||
case _ if asm.size > 1 && isRedeemScript(asm.last) => true
|
||||
case _ if WitnessScriptPubKey.isWitnessScriptPubKey(asm) => true
|
||||
case _ => false
|
||||
def isP2SHScriptSig(asm: Seq[ScriptToken]): Boolean = {
|
||||
asm.size > 1 && isRedeemScript(asm.last)
|
||||
}
|
||||
|
||||
/** Detects if the given script token is a redeem script */
|
||||
|
@ -508,9 +497,7 @@ object ScriptSignature extends ScriptFactory[ScriptSignature] {
|
|||
/** Creates a scriptSignature from the list of script tokens */
|
||||
def fromAsm(tokens: Seq[ScriptToken]): ScriptSignature = tokens match {
|
||||
case Nil => EmptyScriptSignature
|
||||
case _
|
||||
if (tokens.size > 1 && P2SHScriptSignature.isRedeemScript(
|
||||
tokens.last)) =>
|
||||
case _ if P2SHScriptSignature.isP2SHScriptSig(tokens) =>
|
||||
P2SHScriptSignature.fromAsm(tokens)
|
||||
case _ if ConditionalScriptSignature.isValidConditionalScriptSig(tokens) =>
|
||||
ConditionalScriptSignature.fromAsm(tokens)
|
||||
|
@ -524,41 +511,4 @@ object ScriptSignature extends ScriptFactory[ScriptSignature] {
|
|||
P2PKScriptSignature.fromAsm(tokens)
|
||||
case _ => NonStandardScriptSignature.fromAsm(tokens)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a script signature from the given tokens and scriptPubKey
|
||||
* @param tokens the script signature's tokens
|
||||
* @param scriptPubKey the scriptPubKey which the script signature is trying to spend
|
||||
* @return
|
||||
*/
|
||||
def fromScriptPubKey(
|
||||
tokens: Seq[ScriptToken],
|
||||
scriptPubKey: ScriptPubKey): Try[ScriptSignature] = scriptPubKey match {
|
||||
case _: P2SHScriptPubKey => Try(P2SHScriptSignature.fromAsm(tokens))
|
||||
case _: P2PKHScriptPubKey => Try(P2PKHScriptSignature.fromAsm(tokens))
|
||||
case _: P2PKScriptPubKey => Try(P2PKScriptSignature.fromAsm(tokens))
|
||||
case _: MultiSignatureScriptPubKey =>
|
||||
Try(MultiSignatureScriptSignature.fromAsm(tokens))
|
||||
case _: NonStandardScriptPubKey =>
|
||||
Try(NonStandardScriptSignature.fromAsm(tokens))
|
||||
case s: CLTVScriptPubKey => fromScriptPubKey(tokens, s.nestedScriptPubKey)
|
||||
case s: CSVScriptPubKey => fromScriptPubKey(tokens, s.nestedScriptPubKey)
|
||||
case _: ConditionalScriptPubKey =>
|
||||
Try(ConditionalScriptSignature.fromAsm(tokens))
|
||||
case _: WitnessScriptPubKeyV0 | _: UnassignedWitnessScriptPubKey =>
|
||||
Success(EmptyScriptSignature)
|
||||
case EmptyScriptPubKey =>
|
||||
if (tokens.isEmpty) Success(EmptyScriptSignature)
|
||||
else Try(NonStandardScriptSignature.fromAsm(tokens))
|
||||
case _: WitnessCommitment =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Cannot spend witness commitment scriptPubKey"))
|
||||
}
|
||||
|
||||
def apply(
|
||||
tokens: Seq[ScriptToken],
|
||||
scriptPubKey: ScriptPubKey): Try[ScriptSignature] = {
|
||||
fromScriptPubKey(tokens, scriptPubKey)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ package org.bitcoins.core.script
|
|||
*/
|
||||
sealed abstract class ScriptType {
|
||||
import org.bitcoins.core.script.ScriptType._
|
||||
override def toString = this match {
|
||||
override def toString: String = this match {
|
||||
case NONSTANDARD => "nonstandard"
|
||||
case PUBKEY => "pubkey"
|
||||
case PUBKEYHASH => "pubkeyhash"
|
||||
|
@ -30,15 +30,15 @@ sealed abstract class ScriptType {
|
|||
* from Bitcoin Core
|
||||
*/
|
||||
object ScriptType {
|
||||
private val all: Seq[ScriptType] = Vector(NONSTANDARD,
|
||||
PUBKEY,
|
||||
PUBKEYHASH,
|
||||
SCRIPTHASH,
|
||||
MULTISIG,
|
||||
NULLDATA,
|
||||
WITNESS_V0_KEYHASH,
|
||||
WITNESS_V0_SCRIPTHASH,
|
||||
WITNESS_UNKNOWN)
|
||||
private[script] val all: Seq[ScriptType] = Vector(NONSTANDARD,
|
||||
PUBKEY,
|
||||
PUBKEYHASH,
|
||||
SCRIPTHASH,
|
||||
MULTISIG,
|
||||
NULLDATA,
|
||||
WITNESS_V0_KEYHASH,
|
||||
WITNESS_V0_SCRIPTHASH,
|
||||
WITNESS_UNKNOWN)
|
||||
|
||||
def fromString(string: String): Option[ScriptType] =
|
||||
all.find(_.toString == string)
|
||||
|
|
|
@ -348,10 +348,7 @@ sealed abstract class P2WPKHSigner extends BitcoinSigner[P2WPKHV0SpendingInfo] {
|
|||
unsignedTxWitness)
|
||||
|
||||
val witSPK = output.scriptPubKey match {
|
||||
case p2wpkh: P2WPKHWitnessSPKV0 =>
|
||||
if (p2wpkh != P2WPKHWitnessSPKV0(pubKey)) {
|
||||
Future.fromTry(TxBuilderError.WrongPublicKey)
|
||||
} else Future.successful(p2wpkh)
|
||||
case p2wpkh: P2WPKHWitnessSPKV0 => Future.successful(p2wpkh)
|
||||
case _: UnassignedWitnessScriptPubKey | _: P2WSHWitnessSPKV0 =>
|
||||
Future.fromTry(TxBuilderError.WrongSigner)
|
||||
case _: NonWitnessScriptPubKey =>
|
||||
|
|
Loading…
Add table
Reference in a new issue