revise locktime values for CLTV/CSVScriptPubKeys, refactor minimalScriptNumberRepresentation to return a ScriptNumber

This commit is contained in:
Tom McCabe 2016-09-20 14:38:29 -05:00
parent 18745d58e0
commit 563d901ac6
5 changed files with 32 additions and 38 deletions

View file

@ -336,6 +336,7 @@ object P2PKScriptPubKey extends Factory[P2PKScriptPubKey] {
sealed trait CLTVScriptPubKey extends ScriptPubKey {
/**
* Determines the nested ScriptPubKey inside the CLTVScriptPubKey
*
* @return
*/
def scriptPubKeyAfterCLTV : ScriptPubKey = {
@ -348,17 +349,15 @@ sealed trait CLTVScriptPubKey extends ScriptPubKey {
/**
* The absolute CLTV-LockTime value (i.e. the output will remain unspendable until this timestamp or block height)
*
* @return
*/
def locktime : ScriptNumber = {
val bool = asm.head.isInstanceOf[ScriptNumberOperation]
bool match {
case true =>
val op = ScriptNumberOperation(asm.head.hex)
ScriptNumber(op.get.underlying)
case false =>
val hex = BitcoinSUtil.flipEndianess(asm(1).hex)
ScriptNumber(hex)
asm.head match {
case scriptNumOp: ScriptNumberOperation => ScriptNumber(scriptNumOp.underlying)
case pushBytes : BytesToPushOntoStack => ScriptNumber(asm(1).hex)
case x @ (_ : ScriptConstant | _ : ScriptOperation) => throw new IllegalArgumentException("In a CLTVScriptPubKey, " +
"the first asm must be either a ScriptNumberOperation (i.e. OP_5), or the BytesToPushOntoStack for the proceeding ScriptConstant.")
}
}
}
@ -381,8 +380,8 @@ object CLTVScriptPubKey extends Factory[CLTVScriptPubKey] {
def apply(locktime : ScriptNumber, scriptPubKey : ScriptPubKey) : CLTVScriptPubKey = {
val scriptOp = BitcoinScriptUtil.minimalScriptNumberRepresentation(locktime)
val scriptNum : Seq[ScriptToken] = if (scriptOp.isDefined) {
Seq(scriptOp.get)
val scriptNum : Seq[ScriptToken] = if (scriptOp.isInstanceOf[ScriptNumberOperation]) {
Seq(scriptOp)
} else {
val pushOpsLockTime= BitcoinScriptUtil.calculatePushOp(locktime.bytes)
pushOpsLockTime ++ Seq(ScriptConstant(locktime.bytes))
@ -422,6 +421,7 @@ object CLTVScriptPubKey extends Factory[CLTVScriptPubKey] {
sealed trait CSVScriptPubKey extends ScriptPubKey {
/**
* Determines the nested ScriptPubKey inside the CSVScriptPubKey
*
* @return
*/
def scriptPubKeyAfterCSV : ScriptPubKey = {
@ -434,17 +434,15 @@ sealed trait CSVScriptPubKey extends ScriptPubKey {
/**
* The relative CSV-LockTime value (i.e. the amount of time the output should remain unspendable)
*
* @return
*/
def locktime : ScriptNumber = {
val bool = asm.head.isInstanceOf[ScriptNumberOperation]
bool match {
case true =>
val op = ScriptNumberOperation(asm.head.hex)
ScriptNumber(op.get.underlying)
case false =>
val hex = BitcoinSUtil.flipEndianess(asm(1).hex)
ScriptNumber(hex)
asm.head match {
case scriptNumOp: ScriptNumberOperation => ScriptNumber(scriptNumOp.underlying)
case pushBytes : BytesToPushOntoStack => ScriptNumber(asm(1).hex)
case x @ (_ : ScriptConstant | _ : ScriptOperation) => throw new IllegalArgumentException("In a CSVScriptPubKey, " +
"the first asm must be either a ScriptNumberOperation (i.e. OP_5), or the BytesToPushOntoStack for the proceeding ScriptConstant.")
}
}
@ -469,8 +467,8 @@ object CSVScriptPubKey extends Factory[CSVScriptPubKey] {
def apply(relativeLockTime : ScriptNumber, scriptPubKey : ScriptPubKey) : CSVScriptPubKey = {
val scriptOp = BitcoinScriptUtil.minimalScriptNumberRepresentation(relativeLockTime)
val scriptNum : Seq[ScriptToken] = if (scriptOp.isDefined) {
Seq(scriptOp.get)
val scriptNum : Seq[ScriptToken] = if (scriptOp.isInstanceOf[ScriptNumberOperation]) {
Seq(scriptOp)
} else {
val pushOpsLockTime= BitcoinScriptUtil.calculatePushOp(relativeLockTime.bytes)
pushOpsLockTime ++ Seq(ScriptConstant(relativeLockTime.bytes))

View file

@ -521,8 +521,7 @@ object ScriptSignature extends Factory[ScriptSignature] with BitcoinSLogger {
case s : NonStandardScriptPubKey => NonStandardScriptSignature.fromAsm(tokens)
case s : CLTVScriptPubKey => fromScriptPubKey(tokens, s.scriptPubKeyAfterCLTV)
case s : CSVScriptPubKey => fromScriptPubKey(tokens, s.scriptPubKeyAfterCSV)
case EmptyScriptPubKey if (tokens.size == 0) => EmptyScriptSignature
case EmptyScriptPubKey => NonStandardScriptSignature.fromAsm(tokens)
case EmptyScriptPubKey => if (tokens.isEmpty) EmptyScriptSignature else NonStandardScriptSignature.fromAsm(tokens)
}
def apply(tokens : Seq[ScriptToken], scriptPubKey : ScriptPubKey) : ScriptSignature = fromScriptPubKey(tokens, scriptPubKey)

View file

@ -309,10 +309,9 @@ trait BitcoinScriptUtil {
return true
}
def minimalScriptNumberRepresentation(num : ScriptNumber) : Option[ScriptOperation] = {
val str = num.underlying.toInt.toString
val op = Try(ScriptOperation.fromString(str))
op.get
def minimalScriptNumberRepresentation(num : ScriptNumber) : ScriptNumber = {
val op = ScriptNumberOperation.fromNumber(num.toInt)
if (op.isDefined) op.get else num
}
}

View file

@ -38,13 +38,11 @@ class ScriptPubKeyTest extends FlatSpec with MustMatchers {
val pubKey = ECPrivateKey().publicKey
val p2pkh = P2PKHScriptPubKey(pubKey)
it must "determine the correct underlying scriptPubKey inside a CLTVScriptPubKey" in {
it must "determine the correct underlying scriptPubKey, and locktime inside a CLTVScriptPubKey" in {
CLTVScriptPubKey(scriptNum17, p2pkh).scriptPubKeyAfterCLTV must be (p2pkh)
CLTVScriptPubKey(scriptNum5, p2pkh).scriptPubKeyAfterCLTV must be (p2pkh)
CLTVScriptPubKey(negativeOne, p2pkh).scriptPubKeyAfterCLTV must be (p2pkh)
}
it must "determine the correct locktime for the CLTVScriptPubKey" in {
CLTVScriptPubKey(scriptNum17, p2pkh).locktime must be (scriptNum17)
CLTVScriptPubKey(scriptNum5, p2pkh).locktime must be (scriptNum5)
}
@ -56,14 +54,13 @@ class ScriptPubKeyTest extends FlatSpec with MustMatchers {
csv.asm must be (expectedCSVAsm)
}
it must "determine the correct underlying scriptPubKey inside a CLTVScriptPubKey" in {
it must "determine the correct underlying scriptPubKey, and locktime inside a CSVScriptPubKey" in {
CSVScriptPubKey(scriptNum17, p2pkh).scriptPubKeyAfterCSV must be (p2pkh)
CSVScriptPubKey(scriptNum5, p2pkh).scriptPubKeyAfterCSV must be (p2pkh)
CSVScriptPubKey(negativeOne, p2pkh).scriptPubKeyAfterCSV must be (p2pkh)
}
it must "determine the correct locktime for the CLTVScriptPubKey" in {
CSVScriptPubKey(scriptNum17, p2pkh).locktime must be (scriptNum17)
CSVScriptPubKey(scriptNum5, p2pkh).locktime must be (scriptNum5)
}
}

View file

@ -190,11 +190,12 @@ class BitcoinScriptUtilTest extends FlatSpec with MustMatchers {
val scriptNumZero = ScriptNumber(0)
val scriptNum16 = ScriptNumber(16)
val scriptNum17 = ScriptNumber(17)
BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNum100) must be (None)
BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNum10) must be (Some(OP_10))
BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNumZero) must be (Some(OP_0))
BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNum16) must be (Some(OP_16))
BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNum17) must be (None)
BitcoinScriptUtil.minimalScriptNumberRepresentation(ScriptNumber(-1)) must be (None)
BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNum100) must be (scriptNum100)
BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNum10) must be (OP_10)
BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNumZero) must be (OP_0)
BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNum16) must be (OP_16)
BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNum17) must be (scriptNum17)
BitcoinScriptUtil.minimalScriptNumberRepresentation(ScriptNumber(-1)) must be (OP_1NEGATE)
BitcoinScriptUtil.minimalScriptNumberRepresentation(ScriptNumber(-2)) must be (ScriptNumber(-2))
}
}