mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-24 23:08:31 +01:00
Adding more documentation to types in the Script language class hierarchy
This commit is contained in:
parent
5b06e2e066
commit
9bb5f60bf4
4 changed files with 88 additions and 6 deletions
|
@ -335,6 +335,10 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter {
|
||||||
logger.error("Cannot perform arithmetic operation on a number larger than 4 bytes, here is the number: " + s)
|
logger.error("Cannot perform arithmetic operation on a number larger than 4 bytes, here is the number: " + s)
|
||||||
ScriptProgramFactory.factory(program,false)
|
ScriptProgramFactory.factory(program,false)
|
||||||
}
|
}
|
||||||
|
case s : ScriptConstant =>
|
||||||
|
val interpretedNumber = ScriptNumberFactory.fromNumber(BitcoinSUtil.hexToLong(s.hex))
|
||||||
|
val newProgram = ScriptProgramFactory.factory(program, interpretedNumber :: program.stack.tail, ScriptProgramFactory.Stack)
|
||||||
|
performUnaryArithmeticOperation(newProgram, op)
|
||||||
case s : ScriptToken =>
|
case s : ScriptToken =>
|
||||||
logger.error("Stack top must be a script number to perform an arithmetic operation")
|
logger.error("Stack top must be a script number to perform an arithmetic operation")
|
||||||
ScriptProgramFactory.factory(program,false)
|
ScriptProgramFactory.factory(program,false)
|
||||||
|
@ -364,9 +368,16 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter {
|
||||||
val newProgram = ScriptProgramFactory.factory(program, interpretedNumber :: program.stack.tail, ScriptProgramFactory.Stack)
|
val newProgram = ScriptProgramFactory.factory(program, interpretedNumber :: program.stack.tail, ScriptProgramFactory.Stack)
|
||||||
performBinaryArithmeticOperation(newProgram, op)
|
performBinaryArithmeticOperation(newProgram, op)
|
||||||
case (x : ScriptNumber, y : ScriptConstant) =>
|
case (x : ScriptNumber, y : ScriptConstant) =>
|
||||||
|
//interpret y as a number
|
||||||
val interpretedNumber = ScriptNumberFactory.fromNumber(BitcoinSUtil.hexToLong(y.hex))
|
val interpretedNumber = ScriptNumberFactory.fromNumber(BitcoinSUtil.hexToLong(y.hex))
|
||||||
val newProgram = ScriptProgramFactory.factory(program, x :: interpretedNumber :: program.stack.tail, ScriptProgramFactory.Stack)
|
val newProgram = ScriptProgramFactory.factory(program, x :: interpretedNumber :: program.stack.tail, ScriptProgramFactory.Stack)
|
||||||
performBinaryArithmeticOperation(newProgram, op)
|
performBinaryArithmeticOperation(newProgram, op)
|
||||||
|
case (x : ScriptConstant, y : ScriptConstant) =>
|
||||||
|
//interpret x and y as a number
|
||||||
|
val interpretedNumberX = ScriptNumberFactory.fromNumber(BitcoinSUtil.hexToLong(x.hex))
|
||||||
|
val interpretedNumberY = ScriptNumberFactory.fromNumber(BitcoinSUtil.hexToLong(y.hex))
|
||||||
|
val newProgram = ScriptProgramFactory.factory(program, interpretedNumberX :: interpretedNumberY :: program.stack.tail.tail, ScriptProgramFactory.Stack)
|
||||||
|
performBinaryArithmeticOperation(newProgram, op)
|
||||||
case (x : ScriptToken, y : ScriptToken) =>
|
case (x : ScriptToken, y : ScriptToken) =>
|
||||||
logger.error("The top two stack items must be script numbers to perform an arithmetic operation")
|
logger.error("The top two stack items must be script numbers to perform an arithmetic operation")
|
||||||
ScriptProgramFactory.factory(program,false)
|
ScriptProgramFactory.factory(program,false)
|
||||||
|
@ -390,7 +401,22 @@ trait ArithmeticInterpreter extends ControlOperationsInterpreter {
|
||||||
logger.error("Cannot perform boolean operation on a number larger than 4 bytes, one of these two numbers is larger than 4 bytes: " + x + " " + y)
|
logger.error("Cannot perform boolean operation on a number larger than 4 bytes, one of these two numbers is larger than 4 bytes: " + x + " " + y)
|
||||||
ScriptProgramFactory.factory(program,false)
|
ScriptProgramFactory.factory(program,false)
|
||||||
}
|
}
|
||||||
|
case (x : ScriptConstant, y : ScriptNumber) =>
|
||||||
|
//interpret x as a number
|
||||||
|
val interpretedNumber = ScriptNumberFactory.fromNumber(BitcoinSUtil.hexToLong(x.hex))
|
||||||
|
val newProgram = ScriptProgramFactory.factory(program, interpretedNumber :: program.stack.tail, ScriptProgramFactory.Stack)
|
||||||
|
performBinaryBooleanOperation(newProgram, op)
|
||||||
|
case (x : ScriptNumber, y : ScriptConstant) =>
|
||||||
|
//interpret y as a number
|
||||||
|
val interpretedNumber = ScriptNumberFactory.fromNumber(BitcoinSUtil.hexToLong(y.hex))
|
||||||
|
val newProgram = ScriptProgramFactory.factory(program, x :: interpretedNumber :: program.stack.tail, ScriptProgramFactory.Stack)
|
||||||
|
performBinaryBooleanOperation(newProgram, op)
|
||||||
|
case (x : ScriptConstant, y : ScriptConstant) =>
|
||||||
|
//interpret x and y as a number
|
||||||
|
val interpretedNumberX = ScriptNumberFactory.fromNumber(BitcoinSUtil.hexToLong(x.hex))
|
||||||
|
val interpretedNumberY = ScriptNumberFactory.fromNumber(BitcoinSUtil.hexToLong(y.hex))
|
||||||
|
val newProgram = ScriptProgramFactory.factory(program, interpretedNumberX :: interpretedNumberY :: program.stack.tail.tail, ScriptProgramFactory.Stack)
|
||||||
|
performBinaryBooleanOperation(newProgram, op)
|
||||||
case (x : ScriptToken, y : ScriptToken) =>
|
case (x : ScriptToken, y : ScriptToken) =>
|
||||||
logger.error("The top two stack items must be script numbers to perform an arithmetic operation")
|
logger.error("The top two stack items must be script numbers to perform an arithmetic operation")
|
||||||
ScriptProgramFactory.factory(program,false)
|
ScriptProgramFactory.factory(program,false)
|
||||||
|
|
|
@ -6,21 +6,53 @@ import org.scalacoin.util.{BitcoinSUtil}
|
||||||
* Created by chris on 1/6/16.
|
* Created by chris on 1/6/16.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the root class of Script. Every element in the Script language is a
|
||||||
|
* ScriptToken - think of this the same way you think about Object in Java.
|
||||||
|
*/
|
||||||
sealed trait ScriptToken {
|
sealed trait ScriptToken {
|
||||||
|
/**
|
||||||
|
* The hexadecimal representation of this script token
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
def hex : String
|
def hex : String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The byte representation of this script token
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
def bytes = BitcoinSUtil.decodeHex(hex)
|
def bytes = BitcoinSUtil.decodeHex(hex)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The conversion from the byte representation of a token to a number
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
def toLong = BitcoinSUtil.hexToLong(hex)
|
def toLong = BitcoinSUtil.hexToLong(hex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A script operation is an instruction that takes an input and gives an output
|
||||||
|
* Think of these as functions
|
||||||
|
*/
|
||||||
trait ScriptOperation extends ScriptToken {
|
trait ScriptOperation extends ScriptToken {
|
||||||
def opCode : Int
|
def opCode : Int
|
||||||
override def hex : String = BitcoinSUtil.encodeHex(opCode.toByte)
|
override def hex : String = BitcoinSUtil.encodeHex(opCode.toByte)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A constant in the Script language for instance as String or a number
|
||||||
|
*/
|
||||||
sealed trait ScriptConstant extends ScriptToken
|
sealed trait ScriptConstant extends ScriptToken
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a number in the Script language
|
||||||
|
*/
|
||||||
sealed trait ScriptNumber extends ScriptConstant {
|
sealed trait ScriptNumber extends ScriptConstant {
|
||||||
|
/**
|
||||||
|
* The underlying number of the ScriptNumber
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
def num : Long
|
def num : Long
|
||||||
|
|
||||||
def + (that : ScriptNumber) : ScriptNumber = ScriptNumberFactory.fromNumber(num + that.num)
|
def + (that : ScriptNumber) : ScriptNumber = ScriptNumberFactory.fromNumber(num + that.num)
|
||||||
|
@ -34,6 +66,13 @@ sealed trait ScriptNumber extends ScriptConstant {
|
||||||
def > (that : ScriptNumber) : Boolean = num > that.num
|
def > (that : ScriptNumber) : Boolean = num > that.num
|
||||||
def >= (that : ScriptNumber) : Boolean = num >= that.num
|
def >= (that : ScriptNumber) : Boolean = num >= that.num
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This equality just checks that the underlying scala numbers are equivalent, NOT if the numbers
|
||||||
|
* are bitwise equivalent in Script. For instance ScriptNumber(0x01).numEqual(ScriptNumber(0x00000000001)) == true
|
||||||
|
* but (ScriptNumber(0x01) == (ScriptNumber(0x00000000001))) == false
|
||||||
|
* @param that
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
def numEqual(that : ScriptNumber) : Boolean = num == that.num
|
def numEqual(that : ScriptNumber) : Boolean = num == that.num
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,11 +85,16 @@ sealed trait ScriptNumber extends ScriptConstant {
|
||||||
case class ScriptNumberImpl(num : Long, override val hex : String) extends ScriptNumber
|
case class ScriptNumberImpl(num : Long, override val hex : String) extends ScriptNumber
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Companion object for ScriptNumberImpl that gives us access to more constructor types for the
|
||||||
|
* ScriptNumberImpl case class
|
||||||
|
*/
|
||||||
object ScriptNumberImpl {
|
object ScriptNumberImpl {
|
||||||
def apply(num : Long) : ScriptNumber = ScriptNumberImpl(num, BitcoinSUtil.longToHex(num))
|
def apply(num : Long) : ScriptNumber = ScriptNumberImpl(num, BitcoinSUtil.longToHex(num))
|
||||||
def apply(hex : String) : ScriptNumber = ScriptNumberImpl(BitcoinSUtil.hexToLong(hex), hex)
|
def apply(hex : String) : ScriptNumber = ScriptNumberImpl(BitcoinSUtil.hexToLong(hex), hex)
|
||||||
def apply(bytes : Seq[Byte]) : ScriptNumber = ScriptNumberImpl(BitcoinSUtil.encodeHex(bytes))
|
def apply(bytes : Seq[Byte]) : ScriptNumber = ScriptNumberImpl(BitcoinSUtil.encodeHex(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed trait ScriptBoolean extends ScriptNumber
|
sealed trait ScriptBoolean extends ScriptNumber
|
||||||
|
|
||||||
//TODO: Need to remove ScriptTrue & ScriptFalse - make OP_TRUE/FALSE inherit from ScriptBoolean
|
//TODO: Need to remove ScriptTrue & ScriptFalse - make OP_TRUE/FALSE inherit from ScriptBoolean
|
||||||
|
|
|
@ -390,4 +390,16 @@ class ArithmeticInterpreterTest extends FlatSpec with MustMatchers with Arithmet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
it must "interpret two script constants as numbers and then add them" in {
|
||||||
|
val scriptConstant1 = ScriptConstantFactory.fromHex("ffffffff")
|
||||||
|
val scriptConstant2 = ScriptConstantFactory.fromHex("ffffff7f")
|
||||||
|
val stack = List(scriptConstant1, scriptConstant2)
|
||||||
|
val script = List(OP_ADD)
|
||||||
|
val program = ScriptProgramFactory.factory(TestUtil.testProgram, stack, script)
|
||||||
|
val newProgram = opAdd(program)
|
||||||
|
newProgram.stack must be (List(OP_0))
|
||||||
|
newProgram.script.isEmpty must be (true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,12 @@ class ScriptInterpreterTest extends FlatSpec with MustMatchers with ScriptInterp
|
||||||
val source = scala.io.Source.fromFile("src/test/scala/org/scalacoin/script/interpreter/script_valid.json")
|
val source = scala.io.Source.fromFile("src/test/scala/org/scalacoin/script/interpreter/script_valid.json")
|
||||||
|
|
||||||
//use this to represent a single test case from script_valid.json
|
//use this to represent a single test case from script_valid.json
|
||||||
/* val lines =
|
val lines =
|
||||||
"""
|
"""
|
||||||
|
|
|
|
||||||
|[["0x4c 0x00","0 EQUAL", "P2SH,STRICTENC"]]
|
|[["''", "RIPEMD160 0x14 0x9c1185a5c5e9fc54612808977ee8f548b2258d31 EQUAL", "P2SH,STRICTENC"]]
|
||||||
""".stripMargin*/
|
""".stripMargin
|
||||||
val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close()
|
//val lines = try source.getLines.filterNot(_.isEmpty).map(_.trim) mkString "\n" finally source.close()
|
||||||
val json = lines.parseJson
|
val json = lines.parseJson
|
||||||
val testCasesOpt : Seq[Option[CoreTestCase]] = json.convertTo[Seq[Option[CoreTestCase]]]
|
val testCasesOpt : Seq[Option[CoreTestCase]] = json.convertTo[Seq[Option[CoreTestCase]]]
|
||||||
val testCases : Seq[CoreTestCase] = testCasesOpt.flatten
|
val testCases : Seq[CoreTestCase] = testCasesOpt.flatten
|
||||||
|
|
Loading…
Add table
Reference in a new issue