mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-23 14:50:42 +01:00
Adding functionality to parse a VarInt from a scriptSig, adding TransactionInputFactory
This commit is contained in:
parent
50e6aa0d9d
commit
bf813287d4
6 changed files with 64 additions and 35 deletions
|
@ -2,7 +2,7 @@ package org.scalacoin.crypto
|
||||||
|
|
||||||
import org.scalacoin.marshallers.RawBitcoinSerializerHelper
|
import org.scalacoin.marshallers.RawBitcoinSerializerHelper
|
||||||
import org.scalacoin.marshallers.transaction.RawTransactionOutputParser
|
import org.scalacoin.marshallers.transaction.RawTransactionOutputParser
|
||||||
import org.scalacoin.protocol.script.{ScriptPubKeyFactory, ScriptPubKey}
|
import org.scalacoin.protocol.script.{ScriptSignatureFactory, ScriptSignatureImpl, ScriptPubKeyFactory, ScriptPubKey}
|
||||||
import org.scalacoin.protocol.transaction.{Transaction, TransactionOutput, TransactionInput}
|
import org.scalacoin.protocol.transaction.{Transaction, TransactionOutput, TransactionInput}
|
||||||
import org.scalacoin.script.constant.ScriptToken
|
import org.scalacoin.script.constant.ScriptToken
|
||||||
import org.scalacoin.script.crypto._
|
import org.scalacoin.script.crypto._
|
||||||
|
@ -55,30 +55,12 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def serialize(spendingTransaction : Transaction, nIn : Int, nType : Int, nVersion : Int, nHashTypeIn : HashType) : String = {
|
def serialize(inputIndex : Int, nType : Int, script : ScriptPubKey, hashType : HashType) : String = {
|
||||||
val serializedVersion =spendingTransaction.version.toHexString
|
//remove signatures from all inputs because we cannot sign existing signatures
|
||||||
val serializedNIn = nHashTypeIn match {
|
val txWithInputSigsRemoved = for {
|
||||||
case SIGHASH_ANYONECANPAY => "01"
|
|
||||||
case _ => addPrecedingZero(spendingTransaction.inputs.size.toHexString)
|
|
||||||
}
|
|
||||||
val serializedInputs = for {
|
|
||||||
input <- spendingTransaction.inputs
|
input <- spendingTransaction.inputs
|
||||||
} yield serializeInput(input,nType,nVersion)
|
} yield input.factory(ScriptSignatureFactory.empty)
|
||||||
|
???
|
||||||
val serializedNOut = nHashTypeIn match {
|
|
||||||
case SIGHASH_NONE => "00"
|
|
||||||
case SIGHASH_SINGLE => addPrecedingZero(nIn.toHexString + 1)
|
|
||||||
case _ => addPrecedingZero(spendingTransaction.outputs.size.toHexString)
|
|
||||||
}
|
|
||||||
|
|
||||||
val serializedOutputs = for {
|
|
||||||
(output,index) <- spendingTransaction.outputs.zipWithIndex
|
|
||||||
} yield serializeOutput(output, nType,nVersion,SIGHASH_NONE,-1,-1)
|
|
||||||
|
|
||||||
val serializedLockTime = addPrecedingZero(spendingTransaction.lockTime.toHexString)
|
|
||||||
|
|
||||||
serializedVersion + serializedNIn + serializedInputs.mkString + serializedNOut +
|
|
||||||
serializedOutputs.mkString + serializedLockTime
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,7 +68,7 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
|
||||||
* format
|
* format
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected def removeOpCodeSeparators(script : Seq[ScriptToken]) : String = {
|
def removeOpCodeSeparators(script : Seq[ScriptToken]) : String = {
|
||||||
val scriptWithoutOpCodeSeparators : String = script.filterNot(_ == OP_CODESEPARATOR).map(_.hex).mkString
|
val scriptWithoutOpCodeSeparators : String = script.filterNot(_ == OP_CODESEPARATOR).map(_.hex).mkString
|
||||||
val scriptWithoutOpCodeSeparatorSize = addPrecedingZero((scriptWithoutOpCodeSeparators.size / 2).toHexString)
|
val scriptWithoutOpCodeSeparatorSize = addPrecedingZero((scriptWithoutOpCodeSeparators.size / 2).toHexString)
|
||||||
val expectedScript : ScriptPubKey = ScriptPubKeyFactory.factory(
|
val expectedScript : ScriptPubKey = ScriptPubKeyFactory.factory(
|
||||||
|
@ -96,4 +78,4 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TransactionSignatureSerializerr(override val spendingTransaction : Transaction) extends TransactionSignatureSerializer
|
class BaseTransactionSignatureSerializer(override val spendingTransaction : Transaction) extends TransactionSignatureSerializer
|
||||||
|
|
|
@ -33,7 +33,7 @@ trait RawTransactionInputParser extends RawBitcoinSerializer[Seq[TransactionInpu
|
||||||
logger.debug("VarInt hex: " + ScalacoinUtil.encodeHex(bytes.slice(outPointBytesSize,outPointBytesSize + scriptVarIntSize)))
|
logger.debug("VarInt hex: " + ScalacoinUtil.encodeHex(bytes.slice(outPointBytesSize,outPointBytesSize + scriptVarIntSize)))
|
||||||
val scriptSigVarInt : VarInt = ScalacoinUtil.parseVarInt(bytes.slice(outPointBytesSize,outPointBytesSize + scriptVarIntSize))
|
val scriptSigVarInt : VarInt = ScalacoinUtil.parseVarInt(bytes.slice(outPointBytesSize,outPointBytesSize + scriptVarIntSize))
|
||||||
|
|
||||||
val scriptSigBytes = bytes.slice(outPointBytesSize+ scriptVarIntSize,
|
val scriptSigBytes = bytes.slice(outPointBytesSize + scriptVarIntSize,
|
||||||
outPointBytesSize + scriptVarIntSize + scriptSigVarInt.num.toInt)
|
outPointBytesSize + scriptVarIntSize + scriptSigVarInt.num.toInt)
|
||||||
|
|
||||||
val scriptSig : ScriptSignature = RawScriptSignatureParser.read(scriptSigBytes)
|
val scriptSig : ScriptSignature = RawScriptSignatureParser.read(scriptSigBytes)
|
||||||
|
|
|
@ -7,7 +7,8 @@ import org.scalacoin.protocol.script.ScriptSignature
|
||||||
/**
|
/**
|
||||||
* Created by chris on 12/26/15.
|
* Created by chris on 12/26/15.
|
||||||
*/
|
*/
|
||||||
trait TransactionInput extends TransactionElement {
|
trait TransactionInput extends TransactionElement with TransactionInputFactory {
|
||||||
|
|
||||||
def previousOutput : TransactionOutPoint
|
def previousOutput : TransactionOutPoint
|
||||||
def scriptSignature : ScriptSignature
|
def scriptSignature : ScriptSignature
|
||||||
def sequence : Long
|
def sequence : Long
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.scalacoin.util
|
package org.scalacoin.util
|
||||||
|
|
||||||
|
import org.scalacoin.protocol.script.ScriptSignature
|
||||||
import org.scalacoin.protocol.{VarIntImpl, VarInt}
|
import org.scalacoin.protocol.{VarIntImpl, VarInt}
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
|
@ -96,8 +97,20 @@ trait NumberUtil {
|
||||||
|
|
||||||
def toByteList(long : Long) = BigInt(long).toByteArray.toList
|
def toByteList(long : Long) = BigInt(long).toByteArray.toList
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a VarInt from a string of hex characters
|
||||||
|
* https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
|
||||||
|
* @param hex
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
def parseVarInt(hex : String) : VarInt = parseVarInt(ScalacoinUtil.decodeHex(hex))
|
def parseVarInt(hex : String) : VarInt = parseVarInt(ScalacoinUtil.decodeHex(hex))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a VarInt from a sequence of bytes
|
||||||
|
* https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
|
||||||
|
* @param bytes
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
def parseVarInt(bytes : Seq[Byte]) : VarInt = {
|
def parseVarInt(bytes : Seq[Byte]) : VarInt = {
|
||||||
require(bytes.size > 0, "Cannot parse a VarInt if the byte array is size 0")
|
require(bytes.size > 0, "Cannot parse a VarInt if the byte array is size 0")
|
||||||
//8 bit number
|
//8 bit number
|
||||||
|
@ -112,6 +125,7 @@ trait NumberUtil {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the size of a VarInt in the number of bytes
|
* Returns the size of a VarInt in the number of bytes
|
||||||
|
* https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
|
||||||
* @param byte
|
* @param byte
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@ -126,6 +140,23 @@ trait NumberUtil {
|
||||||
else 9
|
else 9
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a VarInt from a sequence of bytes
|
||||||
|
* https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
|
||||||
|
* @param bytes
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
def parseVarInt(scriptSig : ScriptSignature) : VarInt = {
|
||||||
|
//largest 8 uint
|
||||||
|
val size = scriptSig.size
|
||||||
|
if (size < 255) VarIntImpl(size,1)
|
||||||
|
else if (size < 65536) VarIntImpl(size,3)
|
||||||
|
else if (size < 4294967296L) VarIntImpl(size,5)
|
||||||
|
else VarIntImpl(size,9)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private def parseLong(hex : String) : Long = java.lang.Long.parseLong(hex,16)
|
private def parseLong(hex : String) : Long = java.lang.Long.parseLong(hex,16)
|
||||||
|
|
||||||
private def parseLong(bytes : List[Byte]) : Long = parseLong(ScalacoinUtil.encodeHex(bytes))
|
private def parseLong(bytes : List[Byte]) : Long = parseLong(ScalacoinUtil.encodeHex(bytes))
|
||||||
|
|
|
@ -12,21 +12,24 @@ import org.scalatest.{FlatSpec, MustMatchers}
|
||||||
class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
|
class TransactionSignatureSerializerTest extends FlatSpec with MustMatchers {
|
||||||
|
|
||||||
|
|
||||||
/* "TransactionSignatureSerializer" must "serialize a given script signature without OP_CODESEPARATORS" in {
|
"TransactionSignatureSerializer" must "serialize a given script signature without OP_CODESEPARATORS" in {
|
||||||
|
val txSerializer = new BaseTransactionSignatureSerializer(TestUtil.transaction)
|
||||||
val scriptPubKey = TestUtil.scriptPubKey.asm
|
val scriptPubKey = TestUtil.scriptPubKey.asm
|
||||||
val expectedScript = removeOpCodeSeparators(scriptPubKey)
|
val expectedScript = txSerializer.removeOpCodeSeparators(scriptPubKey)
|
||||||
serializeScriptCode(scriptPubKey) must be (expectedScript)
|
txSerializer.serializeScriptCode(scriptPubKey) must be (expectedScript)
|
||||||
}
|
}
|
||||||
|
|
||||||
it must "serialize a given script with only OP_CODESEPARATORs" in {
|
it must "serialize a given script with only OP_CODESEPARATORs" in {
|
||||||
|
val txSerializer = new BaseTransactionSignatureSerializer(TestUtil.transaction)
|
||||||
val script = List(OP_CODESEPARATOR)
|
val script = List(OP_CODESEPARATOR)
|
||||||
serializeScriptCode(script) must be ("00")
|
txSerializer.serializeScriptCode(script) must be ("00")
|
||||||
}
|
}
|
||||||
|
|
||||||
it must "serialize a given script with mixed in OP_CODESEPARATORs" in {
|
it must "serialize a given script with mixed in OP_CODESEPARATORs" in {
|
||||||
|
val txSerializer = new BaseTransactionSignatureSerializer(TestUtil.transaction)
|
||||||
val script = List(OP_CODESEPARATOR, OP_1, OP_CODESEPARATOR, OP_0, OP_CODESEPARATOR, OP_2)
|
val script = List(OP_CODESEPARATOR, OP_1, OP_CODESEPARATOR, OP_0, OP_CODESEPARATOR, OP_2)
|
||||||
serializeScriptCode(script) must be ("03510052")
|
txSerializer.serializeScriptCode(script) must be ("03510052")
|
||||||
}*/
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package org.scalacoin.util
|
package org.scalacoin.util
|
||||||
|
|
||||||
import org.scalacoin.marshallers.script.{RawScriptSignatureParser, RawScriptPubKeyParser}
|
import org.scalacoin.marshallers.script.{RawScriptSignatureParser, RawScriptPubKeyParser}
|
||||||
import org.scalacoin.marshallers.transaction.RawTransactionParser
|
import org.scalacoin.marshallers.transaction.{RawTransactionInputParser, RawTransactionParser}
|
||||||
import org.scalacoin.protocol.{AssetAddress, BitcoinAddress}
|
import org.scalacoin.protocol.{AssetAddress, BitcoinAddress}
|
||||||
import org.scalacoin.script.ScriptProgramImpl
|
import org.scalacoin.script.ScriptProgramImpl
|
||||||
import org.scalacoin.script.bitwise.{OP_EQUAL, OP_EQUALVERIFY}
|
import org.scalacoin.script.bitwise.{OP_EQUAL, OP_EQUALVERIFY}
|
||||||
|
@ -79,6 +79,18 @@ object TestUtil {
|
||||||
"02c02b00000000000017a914b0b06365c482eb4eabe6e0630029fb8328ea098487e81c0000000000001976a914938da2b50fd6d8acdfa20e30df0e7d8092f0bc7588ac00000000"
|
"02c02b00000000000017a914b0b06365c482eb4eabe6e0630029fb8328ea098487e81c0000000000001976a914938da2b50fd6d8acdfa20e30df0e7d8092f0bc7588ac00000000"
|
||||||
def transaction = RawTransactionParser.read(rawTransaction)
|
def transaction = RawTransactionParser.read(rawTransaction)
|
||||||
|
|
||||||
|
|
||||||
|
//txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6
|
||||||
|
val rawTxInput = "01" +
|
||||||
|
"85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000" +
|
||||||
|
"6f0047304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e87d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f00125512102b022902a0fdd71e831c37e4136c2754a59887be0618fb75336d7ab67e2982ff551ae" +
|
||||||
|
"ffffffff"
|
||||||
|
def txInput = RawTransactionInputParser.read(rawTxInput)
|
||||||
|
//from txid 44e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26ff
|
||||||
|
val rawTxInputs = "02df80e3e6eba7dcd4650281d3c13f140dafbb823a7227a78eb6ee9f6cedd040011b0000006a473044022040f91c48f4011bf2e2edb6621bfa8fb802241de939cb86f1872c99c580ef0fe402204fc27388bc525e1b655b5f5b35f9d601d28602432dd5672f29e0a47f5b8bbb26012102c114f376c98d12a0540c3a81ab99bb1c5234245c05e8239d09f48229f9ebf011ffffffff" +
|
||||||
|
"df80e3e6eba7dcd4650281d3c13f140dafbb823a7227a78eb6ee9f6cedd04001340000006b483045022100cf317c320d078c5b884c44e7488825dab5bcdf3f88c66314ac925770cd8773a7022033fde60d33cc2842ea73fce5d9cf4f8da6fadf414a75b7085efdcd300407f438012102605c23537b27b80157c770cd23e066cd11db3800d3066a38b9b592fc08ae9c70ffffffff"
|
||||||
|
def txInputs = RawTransactionInputParser.read(rawTxInputs)
|
||||||
|
|
||||||
//simple raw transaction with only one input and two outputs
|
//simple raw transaction with only one input and two outputs
|
||||||
//txid 92efdd5abb43efd4fe4f89bd080bcddd287a630e8cb6920388dd7880acf4c964
|
//txid 92efdd5abb43efd4fe4f89bd080bcddd287a630e8cb6920388dd7880acf4c964
|
||||||
val simpleRawTransaction = "0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e690c865c2f6f7a9710a474154ab1423abb5b9288ac00000000"
|
val simpleRawTransaction = "0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e690c865c2f6f7a9710a474154ab1423abb5b9288ac00000000"
|
||||||
|
|
Loading…
Add table
Reference in a new issue