Script Program apply method refactor part 5 (#760) (#801)

* Script Program apply method refactor part 5 (#760)

* Formatting
This commit is contained in:
Ben Carman 2019-10-13 13:20:03 -05:00 committed by Chris Stewart
parent f475808dbd
commit 9d16d723ae
10 changed files with 67 additions and 99 deletions

View file

@ -20,15 +20,11 @@ class ScriptProgramFactoryTest extends FlatSpec with MustMatchers {
val altStack = List(OP_1)
val modifiedStackProgram =
ScriptProgram(TestUtil.testProgramExecutionInProgress,
stack,
ScriptProgram.Stack)
TestUtil.testProgramExecutionInProgress.updateStack(stack)
modifiedStackProgram.stack must be(stack)
val modifiedAltStack =
ScriptProgram(TestUtil.testProgramExecutionInProgress,
altStack,
ScriptProgram.AltStack)
TestUtil.testProgramExecutionInProgress.updateAltStack(altStack)
modifiedAltStack.altStack must be(altStack)
}

View file

@ -24,13 +24,11 @@ class ScriptProgramTest extends FlatSpec with MustMatchers {
ScriptProgram(TestUtil.testProgramExecutionInProgress, stack, script)
program.stackTopIsTrue must be(false)
val program2 = ScriptProgram(program, List(OP_0), ScriptProgram.Stack)
val program2 = program.updateStack(List(OP_0))
program2.stackTopIsTrue must be(false)
//stack top should not be true for negative zero
val program3 = ScriptProgram(program,
List(ScriptNumber.negativeZero),
ScriptProgram.Stack)
val program3 = program.updateStack(List(ScriptNumber.negativeZero))
program3.stackTopIsTrue must be(false)
}
}

View file

@ -217,10 +217,7 @@ class CryptoInterpreterTest extends FlatSpec with MustMatchers {
it must "evaluate an OP_CODESEPARATOR" in {
val stack = List()
val script = Seq(OP_CODESEPARATOR)
val program = ScriptProgram(
ScriptProgram(TestUtil.testProgramExecutionInProgress, stack, script),
script,
ScriptProgram.OriginalScript)
val program = ScriptProgram(TestUtil.testProgramExecutionInProgress, stack, script).updateOriginalScript(script)
val newProgram = ScriptProgramTestUtil.toExecutionInProgressScriptProgram(
CI.opCodeSeparator(program))
newProgram.lastCodeSeparator must be(Some(0))

View file

@ -567,8 +567,7 @@ class StackInterpreterTest extends FlatSpec with MustMatchers {
val altStack = List(OP_0)
val program =
ScriptProgram(TestUtil.testProgramExecutionInProgress, stack, script)
val programWithAltStack =
ScriptProgram(program, altStack, ScriptProgram.AltStack)
val programWithAltStack = program.updateAltStack(altStack)
val executedProgram = SI.opFromAltStack(programWithAltStack)
executedProgram.stack must be(altStack)
}

View file

@ -143,12 +143,33 @@ case class ExecutionInProgressScriptProgram(
/**
* Removes the flags on the given [[org.bitcoins.core.script.ScriptProgram ScriptProgram]]
*
* @return
*/
def removeFlags(): ExecutionInProgressScriptProgram = {
this.replaceFlags(Seq.empty)
}
def updateStack(
tokens: Seq[ScriptToken]): ExecutionInProgressScriptProgram = {
this.copy(stack = tokens.toList)
}
def updateAltStack(
tokens: Seq[ScriptToken]): ExecutionInProgressScriptProgram = {
this.copy(altStack = tokens.toList)
}
def updateScript(
tokens: Seq[ScriptToken]): ExecutionInProgressScriptProgram = {
this.copy(script = tokens.toList)
}
def updateOriginalScript(
tokens: Seq[ScriptToken]): ExecutionInProgressScriptProgram = {
this.copy(originalScript = tokens.toList)
}
def updateLastCodeSeparator(
newLastCodeSeparator: Int): ExecutionInProgressScriptProgram = {
this.copy(lastCodeSeparator = Some(newLastCodeSeparator))
@ -202,57 +223,22 @@ object ScriptProgram extends BitcoinSLogger {
}
def apply(
oldProgram: ExecutionInProgressScriptProgram,
tokens: Seq[ScriptToken],
indicator: UpdateIndicator): ExecutionInProgressScriptProgram = {
indicator match {
case Stack =>
ExecutionInProgressScriptProgram(
oldProgram.txSignatureComponent,
tokens.toList,
oldProgram.script,
oldProgram.originalScript,
oldProgram.altStack,
oldProgram.flags,
oldProgram.lastCodeSeparator
)
case Script =>
ExecutionInProgressScriptProgram(
oldProgram.txSignatureComponent,
oldProgram.stack,
tokens.toList,
oldProgram.originalScript,
oldProgram.altStack,
oldProgram.flags,
oldProgram.lastCodeSeparator
)
case AltStack =>
ExecutionInProgressScriptProgram(
oldProgram.txSignatureComponent,
oldProgram.stack,
oldProgram.script,
oldProgram.originalScript,
tokens.toList,
oldProgram.flags,
oldProgram.lastCodeSeparator
)
case OriginalScript =>
ExecutionInProgressScriptProgram(oldProgram.txSignatureComponent,
oldProgram.stack,
oldProgram.script,
tokens.toList,
oldProgram.altStack,
oldProgram.flags,
oldProgram.lastCodeSeparator)
}
oldProgram: PreExecutionScriptProgram,
stackTokens: Seq[ScriptToken],
scriptTokens: Seq[ScriptToken]): PreExecutionScriptProgram = {
val updatedStack = oldProgram.updateStack(stackTokens)
val updatedScript = updatedStack.updateScript(scriptTokens)
require(updatedStack.stack == stackTokens)
require(updatedScript.script == scriptTokens)
updatedScript
}
def apply(
oldProgram: ExecutionInProgressScriptProgram,
stackTokens: Seq[ScriptToken],
scriptTokens: Seq[ScriptToken]): ExecutionInProgressScriptProgram = {
val updatedStack = ScriptProgram(oldProgram, stackTokens, Stack)
val updatedScript = ScriptProgram(updatedStack, scriptTokens, Script)
val updatedStack = oldProgram.updateStack(stackTokens)
val updatedScript = updatedStack.updateScript(scriptTokens)
require(updatedStack.stack == stackTokens)
require(updatedScript.script == scriptTokens)
updatedScript
@ -266,7 +252,16 @@ object ScriptProgram extends BitcoinSLogger {
tokens: Seq[ScriptToken],
indicator: UpdateIndicator,
lastCodeSeparator: Int): ExecutionInProgressScriptProgram = {
val updatedIndicator = ScriptProgram(oldProgram, tokens, indicator)
val updatedIndicator = indicator match {
case Stack =>
oldProgram.updateStack(tokens)
case AltStack =>
oldProgram.updateAltStack(tokens)
case Script =>
oldProgram.updateScript(tokens)
case OriginalScript =>
oldProgram.updateOriginalScript(tokens)
}
updatedIndicator.updateLastCodeSeparator(lastCodeSeparator)
}
@ -296,11 +291,9 @@ object ScriptProgram extends BitcoinSLogger {
stack: Seq[ScriptToken],
script: Seq[ScriptToken],
altStack: Seq[ScriptToken]): ExecutionInProgressScriptProgram = {
val updatedProgramStack = ScriptProgram(oldProgram, stack, Stack)
val updatedProgramScript =
ScriptProgram(updatedProgramStack, script, Script)
val updatedProgramAltStack =
ScriptProgram(updatedProgramScript, altStack, AltStack)
val updatedProgramStack = oldProgram.updateStack(stack)
val updatedProgramScript = updatedProgramStack.updateScript(script)
val updatedProgramAltStack = updatedProgramScript.updateAltStack(altStack)
updatedProgramAltStack
}

View file

@ -307,10 +307,8 @@ sealed abstract class ArithmeticInterpreter {
program.failExecution(ScriptErrorUnknownError)
} else {
val interpretedNumber = ScriptNumber(ScriptNumberUtil.toLong(s.hex))
val newProgram = ScriptProgram(
program,
interpretedNumber :: program.stack.tail,
ScriptProgram.Stack)
val newProgram =
program.updateStack(interpretedNumber :: program.stack.tail)
performUnaryArithmeticOperation(newProgram, op)
}
case Some(_: ScriptToken) =>
@ -360,26 +358,20 @@ sealed abstract class ArithmeticInterpreter {
case (x: ScriptConstant, _: ScriptNumber) =>
//interpret x as a number
val interpretedNumber = ScriptNumber(x.hex)
val newProgram = ScriptProgram(
program,
interpretedNumber :: program.stack.tail,
ScriptProgram.Stack)
val newProgram =
program.updateStack(interpretedNumber :: program.stack.tail)
performBinaryArithmeticOperation(newProgram, op)
case (x: ScriptNumber, y: ScriptConstant) =>
val interpretedNumber = ScriptNumber(y.hex)
val newProgram = ScriptProgram(
program,
x :: interpretedNumber :: program.stack.tail,
ScriptProgram.Stack)
val newProgram =
program.updateStack(x :: interpretedNumber :: program.stack.tail)
performBinaryArithmeticOperation(newProgram, op)
case (x: ScriptConstant, y: ScriptConstant) =>
//interpret x and y as a number
val interpretedNumberX = ScriptNumber(x.hex)
val interpretedNumberY = ScriptNumber(y.hex)
val newProgram = ScriptProgram(
program,
interpretedNumberX :: interpretedNumberY :: program.stack.tail.tail,
ScriptProgram.Stack)
val newProgram = program.updateStack(
interpretedNumberX :: interpretedNumberY :: program.stack.tail.tail)
performBinaryArithmeticOperation(newProgram, op)
case (_: ScriptToken, _: ScriptToken) =>
//pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here

View file

@ -155,8 +155,7 @@ sealed abstract class ConstantInterpreter {
ScriptNumber.zero :: program.stack,
program.script.tail.tail)
case _: ScriptToken =>
pushScriptNumberBytesToStack(
ScriptProgram(program, program.script, ScriptProgram.Script))
pushScriptNumberBytesToStack(program.updateScript(program.script))
}
}
}

View file

@ -107,7 +107,7 @@ sealed abstract class CryptoInterpreter {
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
val newScript = OP_CHECKSIG :: OP_VERIFY :: program.script.tail
val newProgram = ScriptProgram(program, newScript, ScriptProgram.Script)
val newProgram = program.updateScript(newScript)
val programFromOpCheckSig = opCheckSig(newProgram)
logger.debug(
"Stack after OP_CHECKSIG execution: " + programFromOpCheckSig.stack)
@ -264,7 +264,7 @@ sealed abstract class CryptoInterpreter {
program.failExecution(ScriptErrorInvalidStackOperation)
} else {
val newScript = OP_CHECKMULTISIG :: OP_VERIFY :: program.script.tail
val newProgram = ScriptProgram(program, newScript, ScriptProgram.Script)
val newProgram = program.updateScript(newScript)
val programFromOpCheckMultiSig = opCheckMultiSig(newProgram)
logger.debug(
"Stack after OP_CHECKMULTSIG execution: " + programFromOpCheckMultiSig.stack)

View file

@ -1016,8 +1016,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
calcOpCount(opCount, OP_CHECKLOCKTIMEVERIFY))
} //in this case, just reat OP_CLTV just like a NOP and remove it from the stack
else {
val programOrError =
ScriptProgram(program, program.script.tail, ScriptProgram.Script)
val programOrError = program.updateScript(program.script.tail)
val newOpCount =
calcOpCount(opCount, OP_CHECKLOCKTIMEVERIFY)
(programOrError, newOpCount)
@ -1040,8 +1039,7 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
calcOpCount(opCount, OP_CHECKSEQUENCEVERIFY))
} //in this case, just read OP_CSV just like a NOP and remove it from the stack
else {
val programOrError =
ScriptProgram(program, program.script.tail, ScriptProgram.Script)
val programOrError = program.updateScript(program.script.tail)
val newOpCount =
calcOpCount(opCount, OP_CHECKSEQUENCEVERIFY)
(programOrError, newOpCount)

View file

@ -74,7 +74,7 @@ sealed abstract class LockTimeInterpreter {
//if the number size is larger than 5 bytes the number is invalid
program.failExecution(ScriptErrorUnknownError)
} else if (checkLockTime(program, s)) {
ScriptProgram(program, program.script.tail, ScriptProgram.Script)
program.updateScript(program.script.tail)
} else {
logger.error(
"Stack top locktime and transaction locktime number comparison failed")
@ -82,9 +82,7 @@ sealed abstract class LockTimeInterpreter {
}
case s: ScriptConstant =>
opCheckLockTimeVerify(
ScriptProgram(program,
ScriptNumber(s.hex) :: program.stack.tail,
ScriptProgram.Stack))
program.updateStack(ScriptNumber(s.hex) :: program.stack.tail))
case _: ScriptToken => program.failExecution(ScriptErrorUnknownError)
}
}
@ -121,7 +119,7 @@ sealed abstract class LockTimeInterpreter {
//see BIP68 for semantic of locktimeDisableFlag
logger.info(
"Locktime disable flag was set so OP_CHECKSEQUENCEVERIFY is treated as a NOP")
ScriptProgram(program, program.script.tail, ScriptProgram.Script)
program.updateScript(program.script.tail)
case s: ScriptNumber
if (isLockTimeBitOff(s) && program.txSignatureComponent.transaction.version < TransactionConstants.validLockVersion) =>
logger.error(
@ -140,9 +138,7 @@ sealed abstract class LockTimeInterpreter {
}
case s: ScriptConstant =>
opCheckSequenceVerify(
ScriptProgram(program,
ScriptNumber(s.hex) :: program.stack.tail,
ScriptProgram.Stack))
program.updateStack(ScriptNumber(s.hex) :: program.stack.tail))
case token: ScriptToken =>
throw new RuntimeException(
"Stack top must be either a ScriptConstant or a ScriptNumber, we got: " + token)