implement toInt function for all signed/unsigned numbers, add Int64 boolean operators to ScriptNumber

This commit is contained in:
Tom McCabe 2016-07-05 15:00:27 -05:00
parent de999ab03b
commit 6d4763acf4
7 changed files with 38 additions and 25 deletions

View file

@ -31,7 +31,7 @@ trait TransactionSignatureComponent {
*
* @return
*/
def scriptSignature = transaction.inputs(inputIndex.underlying.toInt).scriptSignature
def scriptSignature = transaction.inputs(inputIndex.toInt).scriptSignature
/**
* The scriptPubKey for which the input is being checked against
*

View file

@ -64,7 +64,7 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper with Bit
logger.info("After Bitcoin-S Script to be connected: " + scriptWithOpCodeSeparatorsRemoved)
val inputToSign = inputSigsRemoved(inputIndex.underlying.toInt)
val inputToSign = inputSigsRemoved(inputIndex.toInt)
// Set the input to the script of its output. Bitcoin Core does this but the step has no obvious purpose as
// the signature covers the hash of the prevout transaction which obviously includes the output script

View file

@ -18,20 +18,20 @@ trait TransactionConstants {
*
* @return the mask that ben used with a bitwise and to indicate if the sequence number has any meaning
*/
def locktimeDisabledFlag = 1L << 31
def locktimeDisabledFlag = UInt32(1L << 31)
/**
* If a transaction's input's sequence number encodes a relative lock-time, this mask is
* applied to extract that lock-time from the sequence field.
*/
def sequenceLockTimeMask = 0x0000ffff
def sequenceLockTimeMask = UInt32(0x0000ffff)
/**
* If the transaction input sequence number encodes a relative lock-time and this flag
* is set, the relative lock-time has units of 512 seconds,
* otherwise it specifies blocks with a granularity of 1.
*/
def sequenceLockTimeTypeFlag = 1L << 22
def sequenceLockTimeTypeFlag = UInt32(1L << 22)
/**

View file

@ -341,7 +341,7 @@ object ScriptProgram {
*/
def factory(transaction: Transaction, scriptPubKey : ScriptPubKey, inputIndex : UInt32,
flags : Seq[ScriptFlag]) : PreExecutionScriptProgram = {
val script = transaction.inputs(inputIndex.underlying.toInt).scriptSignature.asm
val script = transaction.inputs(inputIndex.toInt).scriptSignature.asm
apply(transaction,scriptPubKey,inputIndex,script.toList,flags)
}

View file

@ -1,5 +1,6 @@
package org.bitcoins.core.script.constant
import org.bitcoins.core.number.Int64
import org.bitcoins.core.script.ScriptOperationFactory
import org.bitcoins.core.util.{BitcoinSUtil, BitcoinScriptUtil, Factory}
@ -23,7 +24,8 @@ sealed trait ScriptToken {
/**
* The byte representation of this script token
* @return
*
* @return
*/
def bytes : Seq[Byte] = BitcoinSUtil.decodeHex(hex)
@ -50,7 +52,8 @@ trait ScriptOperation extends ScriptToken {
sealed trait ScriptConstant extends ScriptToken {
/**
* Returns if the constant is encoded in the shortest possible way
* @return
*
* @return
*/
def isShortestEncoding : Boolean = BitcoinScriptUtil.isShortestEncoding(this)
}
@ -62,7 +65,8 @@ sealed trait ScriptConstant extends ScriptToken {
sealed trait ScriptNumber extends ScriptConstant {
/**
* The underlying number of the ScriptNumber
* @return
*
* @return
*/
def underlying : Long
@ -77,7 +81,14 @@ sealed trait ScriptNumber extends ScriptConstant {
def > (that : ScriptNumber) : Boolean = underlying > that.underlying
def >= (that : ScriptNumber) : Boolean = underlying >= that.underlying
def &(that : ScriptNumber) : ScriptNumber = ScriptNumber(underlying & that.underlying)
def < (that : Int64) : Boolean = underlying < that.underlying
def <= (that : Int64) : Boolean = underlying <= that.underlying
def > (that : Int64) : Boolean = underlying > that.underlying
def >= (that : Int64) : Boolean = underlying >= that.underlying
def & (that : ScriptNumber) : ScriptNumber = ScriptNumber(underlying & that.underlying)
def & (that : Int64) : ScriptNumber = ScriptNumber(underlying & that.underlying)
def | (that : ScriptNumber) : ScriptNumber = ScriptNumber(underlying | that.underlying)
@ -85,7 +96,8 @@ sealed trait ScriptNumber extends ScriptConstant {
* 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
*
* @param that
* @return
*/
def numEqual(that : ScriptNumber) : Boolean = underlying == that.underlying
@ -191,6 +203,7 @@ case object OP_PUSHDATA2 extends ScriptOperation {
/**
* The max amount of data that OP_PUSHDATA2 can push onto the stack
*
* @return
*/
def max = 65535
@ -204,6 +217,7 @@ case object OP_PUSHDATA4 extends ScriptOperation {
/**
* The maximum amount of data that OP_PUSHDATA4 can be push on the stack
*
* @return
*/
def max = 4294967295L

View file

@ -131,7 +131,7 @@ trait LockTimeInterpreter extends BitcoinSLogger {
* @return if the given script number is valid or not
*/
def checkSequence(program : ScriptProgram, nSequence : ScriptNumber) : Boolean = {
val inputIndex = program.txSignatureComponent.inputIndex.underlying.toInt
val inputIndex = program.txSignatureComponent.inputIndex.toInt
logger.debug("inputIndex: " + inputIndex)
val transaction = program.txSignatureComponent.transaction
val txToSequence : Int64 = Int64(transaction.inputs(inputIndex).sequence.underlying)
@ -141,10 +141,9 @@ trait LockTimeInterpreter extends BitcoinSLogger {
return false
}
val nLockTimeMask : UInt32 = UInt32(TransactionConstants.sequenceLockTimeTypeFlag | TransactionConstants.sequenceLockTimeMask)
val txToSequenceMasked : Int64 = Int64(txToSequence.underlying & Int64(nLockTimeMask.underlying).underlying)
val nSequenceMasked : ScriptNumber = nSequence & ScriptNumber(nLockTimeMask.underlying)
val nLockTimeMask : UInt32 = UInt32(TransactionConstants.sequenceLockTimeTypeFlag.underlying | TransactionConstants.sequenceLockTimeMask.underlying)
val txToSequenceMasked : Int64 = Int64(txToSequence.underlying & nLockTimeMask.underlying)
val nSequenceMasked : ScriptNumber = nSequence & Int64(nLockTimeMask.underlying)
logger.info("tx sequence number: " + transaction.inputs(inputIndex).sequence)
logger.info("txToSequenceMasked: " + txToSequenceMasked)
@ -159,10 +158,10 @@ trait LockTimeInterpreter extends BitcoinSLogger {
// unless the type of nSequenceMasked being tested is the same as
// the nSequenceMasked in the transaction.
if (!(
(txToSequenceMasked.underlying < TransactionConstants.sequenceLockTimeTypeFlag &&
nSequenceMasked.underlying < TransactionConstants.sequenceLockTimeTypeFlag) ||
(txToSequenceMasked.underlying >= TransactionConstants.sequenceLockTimeTypeFlag &&
nSequenceMasked.underlying >= TransactionConstants.sequenceLockTimeTypeFlag)
(txToSequenceMasked < Int64(TransactionConstants.sequenceLockTimeTypeFlag.underlying) &&
nSequenceMasked < Int64(TransactionConstants.sequenceLockTimeTypeFlag.underlying)) ||
(txToSequenceMasked >= Int64(TransactionConstants.sequenceLockTimeTypeFlag.underlying) &&
nSequenceMasked >= Int64(TransactionConstants.sequenceLockTimeTypeFlag.underlying))
)) {
logger.error("The nSequence mask is not the same as it was in the transaction")
return false
@ -170,7 +169,7 @@ trait LockTimeInterpreter extends BitcoinSLogger {
// Now that we know we're comparing apples-to-apples, the
// comparison is a simple numeric one.
if (nSequenceMasked.underlying > txToSequenceMasked.underlying) {
if (nSequenceMasked > Int64(txToSequenceMasked.underlying)) {
logger.error("OP_CSV fails because locktime in transaction has not been met yet")
return false
}
@ -195,7 +194,7 @@ trait LockTimeInterpreter extends BitcoinSLogger {
// unless the type of nLockTime being tested is the same as
// the nLockTime in the transaction.
val transaction = program.txSignatureComponent.transaction
val input = transaction.inputs(program.txSignatureComponent.inputIndex.underlying.toInt)
val input = transaction.inputs(program.txSignatureComponent.inputIndex.toInt)
if (!(
(transaction.lockTime < TransactionConstants.locktimeThreshold && UInt32(locktime.underlying) < TransactionConstants.locktimeThreshold) ||
(transaction.lockTime >= TransactionConstants.locktimeThreshold && UInt32(locktime.underlying) >= TransactionConstants.locktimeThreshold)
@ -203,7 +202,7 @@ trait LockTimeInterpreter extends BitcoinSLogger {
// Now that we know we're comparing apples-to-apples, the
// comparison is a simple numeric one.
if (locktime.underlying > Int64(transaction.lockTime.underlying).underlying) return false
if (locktime > Int64(transaction.lockTime.underlying)) return false
// Finally the nLockTime feature can be disabled and thus
// CHECKLOCKTIMEVERIFY bypassed if every txin has been
@ -226,5 +225,5 @@ trait LockTimeInterpreter extends BitcoinSLogger {
* @param s
* @return
*/
def isLockTimeBitOff(s : ScriptNumber) : Boolean = (s.underlying & TransactionConstants.locktimeDisabledFlag) == 0
def isLockTimeBitOff(s : ScriptNumber) : Boolean = (s.underlying & TransactionConstants.locktimeDisabledFlag.underlying) == 0
}

View file

@ -147,7 +147,7 @@ class LockTimeInterpreterTest extends FlatSpec with MustMatchers with LockTimeIn
}
it must "treat OP_CHECKSEQUENCEVERIFY as a NOP if the locktime disabled flag is set in the sequence number" in {
val stack = List(ScriptNumber(TransactionConstants.locktimeDisabledFlag))
val stack = List(ScriptNumber(TransactionConstants.locktimeDisabledFlag.underlying))
val script = List(OP_CHECKSEQUENCEVERIFY)
val program = ScriptProgram(TestUtil.testProgramExecutionInProgress,stack,script)
val newProgram = opCheckSequenceVerify(program)