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.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.script.constant.ScriptToken
|
||||
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 = {
|
||||
val serializedVersion =spendingTransaction.version.toHexString
|
||||
val serializedNIn = nHashTypeIn match {
|
||||
case SIGHASH_ANYONECANPAY => "01"
|
||||
case _ => addPrecedingZero(spendingTransaction.inputs.size.toHexString)
|
||||
}
|
||||
val serializedInputs = for {
|
||||
def serialize(inputIndex : Int, nType : Int, script : ScriptPubKey, hashType : HashType) : String = {
|
||||
//remove signatures from all inputs because we cannot sign existing signatures
|
||||
val txWithInputSigsRemoved = for {
|
||||
input <- spendingTransaction.inputs
|
||||
} yield serializeInput(input,nType,nVersion)
|
||||
|
||||
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
|
||||
} yield input.factory(ScriptSignatureFactory.empty)
|
||||
???
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,7 +68,7 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
|
|||
* format
|
||||
* @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 scriptWithoutOpCodeSeparatorSize = addPrecedingZero((scriptWithoutOpCodeSeparators.size / 2).toHexString)
|
||||
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)))
|
||||
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)
|
||||
|
||||
val scriptSig : ScriptSignature = RawScriptSignatureParser.read(scriptSigBytes)
|
||||
|
|
|
@ -7,7 +7,8 @@ import org.scalacoin.protocol.script.ScriptSignature
|
|||
/**
|
||||
* Created by chris on 12/26/15.
|
||||
*/
|
||||
trait TransactionInput extends TransactionElement {
|
||||
trait TransactionInput extends TransactionElement with TransactionInputFactory {
|
||||
|
||||
def previousOutput : TransactionOutPoint
|
||||
def scriptSignature : ScriptSignature
|
||||
def sequence : Long
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.scalacoin.util
|
||||
|
||||
import org.scalacoin.protocol.script.ScriptSignature
|
||||
import org.scalacoin.protocol.{VarIntImpl, VarInt}
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
|
@ -96,8 +97,20 @@ trait NumberUtil {
|
|||
|
||||
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))
|
||||
|
||||
/**
|
||||
* 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 = {
|
||||
require(bytes.size > 0, "Cannot parse a VarInt if the byte array is size 0")
|
||||
//8 bit number
|
||||
|
@ -112,6 +125,7 @@ trait NumberUtil {
|
|||
|
||||
/**
|
||||
* Returns the size of a VarInt in the number of bytes
|
||||
* https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
|
||||
* @param byte
|
||||
* @return
|
||||
*/
|
||||
|
@ -126,6 +140,23 @@ trait NumberUtil {
|
|||
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(bytes : List[Byte]) : Long = parseLong(ScalacoinUtil.encodeHex(bytes))
|
||||
|
|
|
@ -12,21 +12,24 @@ import org.scalatest.{FlatSpec, 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 expectedScript = removeOpCodeSeparators(scriptPubKey)
|
||||
serializeScriptCode(scriptPubKey) must be (expectedScript)
|
||||
val expectedScript = txSerializer.removeOpCodeSeparators(scriptPubKey)
|
||||
txSerializer.serializeScriptCode(scriptPubKey) must be (expectedScript)
|
||||
}
|
||||
|
||||
it must "serialize a given script with only OP_CODESEPARATORs" in {
|
||||
val txSerializer = new BaseTransactionSignatureSerializer(TestUtil.transaction)
|
||||
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 {
|
||||
val txSerializer = new BaseTransactionSignatureSerializer(TestUtil.transaction)
|
||||
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
|
||||
|
||||
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.script.ScriptProgramImpl
|
||||
import org.scalacoin.script.bitwise.{OP_EQUAL, OP_EQUALVERIFY}
|
||||
|
@ -79,6 +79,18 @@ object TestUtil {
|
|||
"02c02b00000000000017a914b0b06365c482eb4eabe6e0630029fb8328ea098487e81c0000000000001976a914938da2b50fd6d8acdfa20e30df0e7d8092f0bc7588ac00000000"
|
||||
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
|
||||
//txid 92efdd5abb43efd4fe4f89bd080bcddd287a630e8cb6920388dd7880acf4c964
|
||||
val simpleRawTransaction = "0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e690c865c2f6f7a9710a474154ab1423abb5b9288ac00000000"
|
||||
|
|
Loading…
Add table
Reference in a new issue