mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-20 10:13:26 +01:00
Fixing bug in pushing constants onto the stack whose op codes are ScriptNumberOperations -- for instance pushing an 83 byte transaction (whose op code is OP_3) -- whose script looks like OP_PUSHDATA1 OP_3 <83 byte tx> would fail before this
This commit is contained in:
parent
d8ee3ddb61
commit
3835148f05
@ -37,7 +37,6 @@ trait ConstantInterpreter extends BitcoinSLogger {
|
||||
bytesNeededForPushOp(program.script(1))
|
||||
case _ : ScriptToken => bytesNeededForPushOp(program.script.head)
|
||||
}
|
||||
|
||||
/** Parses the script tokens that need to be pushed onto our stack. */
|
||||
@tailrec
|
||||
def takeUntilBytesNeeded(scriptTokens : List[ScriptToken], accum : List[ScriptToken]) : (List[ScriptToken],List[ScriptToken]) = {
|
||||
@ -56,8 +55,8 @@ trait ConstantInterpreter extends BitcoinSLogger {
|
||||
}
|
||||
|
||||
val (newScript,bytesToPushOntoStack) = program.script.head match {
|
||||
case OP_PUSHDATA1 | OP_PUSHDATA2 | OP_PUSHDATA4 => takeUntilBytesNeeded(program.script.tail.tail, List())
|
||||
case _: ScriptToken => takeUntilBytesNeeded(program.script.tail, List())
|
||||
case OP_PUSHDATA1 | OP_PUSHDATA2 | OP_PUSHDATA4 => takeUntilBytesNeeded(program.script.tail.tail, Nil)
|
||||
case _: ScriptToken => takeUntilBytesNeeded(program.script.tail, Nil)
|
||||
}
|
||||
logger.debug("new script: " + newScript)
|
||||
logger.debug("Bytes to push onto stack: " + bytesToPushOntoStack)
|
||||
@ -73,13 +72,16 @@ trait ConstantInterpreter extends BitcoinSLogger {
|
||||
logger.error("We can push this constant onto the stack with OP_0 - OP_16 instead of using a script constant")
|
||||
ScriptProgram(program,ScriptErrorMinimalData)
|
||||
} else if (bytesNeeded != bytesToPushOntoStack.map(_.bytes.size).sum) {
|
||||
logger.error("Incorrect amount of bytes being pushed onto the stack")
|
||||
logger.error("Bytes needed: " + bytesNeeded)
|
||||
logger.error("Number of byte received: " + bytesToPushOntoStack.map(_.bytes.size).sum)
|
||||
ScriptProgram(program,ScriptErrorBadOpCode)
|
||||
}
|
||||
else if (ScriptFlagUtil.requireMinimalData(program.flags) && !BitcoinScriptUtil.isMinimalPush(program.script.head,constant)) {
|
||||
logger.debug("Pushing operation: " + program.script.head)
|
||||
logger.debug("Constant parsed: " + constant)
|
||||
logger.debug("Constant size: " + constant.bytes.size)
|
||||
ScriptProgram(program,ScriptErrorMinimalData)
|
||||
logger.debug("Pushing operation: " + program.script.head)
|
||||
logger.debug("Constant parsed: " + constant)
|
||||
logger.debug("Constant size: " + constant.bytes.size)
|
||||
ScriptProgram(program,ScriptErrorMinimalData)
|
||||
} else ScriptProgram.apply(program, constant :: program.stack, newScript)
|
||||
}
|
||||
|
||||
@ -90,7 +92,7 @@ trait ConstantInterpreter extends BitcoinSLogger {
|
||||
//constant telling OP_PUSHDATA how many bytes need to go onto the stack
|
||||
//for instance OP_PUSHDATA1 OP_0
|
||||
val scriptNumOp = program.script(1).bytes match {
|
||||
case h :: t => ScriptNumberOperation(h)
|
||||
case h :: t => ScriptNumberOperation.fromNumber(h.toInt)
|
||||
case Nil => None
|
||||
}
|
||||
if (ScriptFlagUtil.requireMinimalData(program.flags) && program.script(1).bytes.size == 1 &&
|
||||
@ -117,6 +119,7 @@ trait ConstantInterpreter extends BitcoinSLogger {
|
||||
/** Parses the bytes needed for a push op (for instance OP_PUSHDATA1). */
|
||||
private def bytesNeededForPushOp(token : ScriptToken) : Long = token match {
|
||||
case scriptNumber: BytesToPushOntoStack => scriptNumber.opCode
|
||||
case scriptNumOp: ScriptNumberOperation => scriptNumOp.opCode
|
||||
case scriptNumber: ScriptNumber => scriptNumber.underlying
|
||||
case scriptConstant : ScriptConstant =>
|
||||
val constantFlippedEndianness = BitcoinSUtil.flipEndianness(scriptConstant.hex)
|
||||
|
@ -127,12 +127,22 @@ class ConstantInterpreterTest extends FlatSpec with MustMatchers with ConstantIn
|
||||
}
|
||||
}
|
||||
|
||||
it must "return ScriptErrorMinimalData if program contains ScriptVerifyMinimalData flag and 2nd item in script is" +
|
||||
" zero" in {
|
||||
it must "return ScriptErrorMinimalData if program contains ScriptVerifyMinimalData flag and 2nd item in script is zero" in {
|
||||
val stack = List()
|
||||
val script = List(OP_PUSHDATA4,ScriptNumber.zero)
|
||||
val program = ScriptProgram(ScriptProgram(TestUtil.testProgram, stack,script),Seq[ScriptFlag](ScriptVerifyMinimalData))
|
||||
val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(opPushData4(program))
|
||||
newProgram.error must be (Some(ScriptErrorMinimalData))
|
||||
}
|
||||
|
||||
it must "push a constant onto the stack that is using OP_PUSHDATA1 where the pushop can be interpreted as a script number operation" in {
|
||||
val constant = ScriptConstant("01000000010000000000000000000000000000000000000000000000000000000000000000" +
|
||||
"ffffffff00ffffffff014a7afa8f7d52fd9e17a914b167f19394cd656c34f843ac2387e602007fd15b8700000000")
|
||||
val stack = Nil
|
||||
val script = List(OP_PUSHDATA1, OP_3, constant)
|
||||
val program = ScriptProgram(TestUtil.testProgram, stack,script)
|
||||
val newProgram = opPushData1(program)
|
||||
newProgram.stack must be (Seq(constant))
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user