mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-19 05:43:51 +01:00
Successfully serializing and deserializing a raw bitcoin output
This commit is contained in:
parent
eac24ded52
commit
bbff4ee676
@ -1,5 +1,7 @@
|
||||
package org.scalacoin.marshallers
|
||||
|
||||
import org.scalacoin.util.ScalacoinUtil
|
||||
|
||||
/**
|
||||
* Created by chris on 1/11/16.
|
||||
*/
|
||||
@ -11,7 +13,9 @@ trait RawBitcoinSerializer[T] {
|
||||
* @param hex
|
||||
* @return
|
||||
*/
|
||||
def read(hex : String) : T
|
||||
def read(hex : String) : T = read(ScalacoinUtil.decodeHex(hex))
|
||||
|
||||
def read(bytes : List[Byte]) : T
|
||||
|
||||
/**
|
||||
* Takes a type T and writes it into the appropriate type T
|
||||
|
@ -11,17 +11,18 @@ import org.scalacoin.util.ScalacoinUtil
|
||||
trait RawScriptPubKeyParser extends RawBitcoinSerializer[ScriptPubKey] with ScriptParser {
|
||||
|
||||
|
||||
override def read(hex : String) : ScriptPubKey = {
|
||||
require(hex.size > 0, "Cannot parse a scriptPubKey from an empty string")
|
||||
val bytes = ScalacoinUtil.decodeHex(hex)
|
||||
override def read(bytes : List[Byte]) : ScriptPubKey = {
|
||||
require(bytes.size > 0, "Cannot parse a scriptPubKey from an empty byte list")
|
||||
//first byte indicates how many bytes the script is
|
||||
val scriptSize = bytes.head
|
||||
|
||||
val script : List[ScriptToken] = parse(bytes.tail)
|
||||
|
||||
//not sure how to get addresses from a scriptPubKey
|
||||
ScriptPubKeyImpl(script,hex,Seq())
|
||||
ScriptPubKeyImpl(script,ScalacoinUtil.encodeHex(bytes),Seq())
|
||||
}
|
||||
|
||||
override def write(scriptPubKey : ScriptPubKey) : String = ???
|
||||
override def write(scriptPubKey : ScriptPubKey) : String = {
|
||||
scriptPubKey.hex
|
||||
}
|
||||
}
|
||||
|
||||
object RawScriptPubKeyParser extends RawScriptPubKeyParser
|
||||
|
@ -10,9 +10,9 @@ import org.scalacoin.util.ScalacoinUtil
|
||||
*/
|
||||
trait RawScriptSignatureParser extends RawBitcoinSerializer[ScriptSignature] with ScriptParser {
|
||||
|
||||
def read(hex : String) : ScriptSignature = {
|
||||
val scriptSig : List[ScriptToken] = parse(ScalacoinUtil.decodeHex(hex))
|
||||
ScriptSignatureImpl(scriptSig,hex)
|
||||
def read(bytes : List[Byte]) : ScriptSignature = {
|
||||
val scriptSig : List[ScriptToken] = parse(bytes)
|
||||
ScriptSignatureImpl(scriptSig,ScalacoinUtil.encodeHex(bytes))
|
||||
}
|
||||
|
||||
def write(scriptSig : ScriptSignature) : String = scriptSig.hex
|
||||
|
@ -9,11 +9,10 @@ import org.scalacoin.util.ScalacoinUtil
|
||||
* https://bitcoin.org/en/developer-reference#outpoint
|
||||
*
|
||||
*/
|
||||
object RawTransactionOutPointMarshaller extends RawBitcoinSerializer[TransactionOutPoint] {
|
||||
trait RawTransactionOutPointMarshaller extends RawBitcoinSerializer[TransactionOutPoint] {
|
||||
|
||||
|
||||
def read(str : String) : TransactionOutPoint = {
|
||||
val bytes = ScalacoinUtil.decodeHex(str)
|
||||
override def read(bytes : List[Byte]) : TransactionOutPoint = {
|
||||
val txId : List[Byte] = bytes.slice(0,16)
|
||||
val index : BigInt = BigInt(bytes.slice(16, bytes.size).toArray)
|
||||
TransactionOutPointImpl(ScalacoinUtil.encodeHex(txId), index.toInt)
|
||||
@ -25,3 +24,6 @@ object RawTransactionOutPointMarshaller extends RawBitcoinSerializer[Transaction
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
object RawTransactionOutPointMarshaller extends RawTransactionOutPointMarshaller
|
||||
|
@ -1,29 +1,57 @@
|
||||
package org.scalacoin.marshallers.transaction
|
||||
|
||||
import org.scalacoin.currency.Satoshis
|
||||
import org.scalacoin.currency.{CurrencyUnits, Satoshis}
|
||||
import org.scalacoin.marshallers.RawBitcoinSerializer
|
||||
import org.scalacoin.marshallers.script.ScriptParser
|
||||
import org.scalacoin.marshallers.script.{RawScriptPubKeyParser, ScriptParser}
|
||||
import org.scalacoin.protocol.transaction.{TransactionOutputImpl, TransactionOutput}
|
||||
import org.scalacoin.util.ScalacoinUtil
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
/**
|
||||
* Created by chris on 1/11/16.
|
||||
* https://bitcoin.org/en/developer-reference#txout
|
||||
*/
|
||||
object RawTransactionOutputParser extends RawBitcoinSerializer[Seq[TransactionOutput]] with ScriptParser {
|
||||
trait RawTransactionOutputParser extends RawBitcoinSerializer[Seq[TransactionOutput]] with ScriptParser {
|
||||
|
||||
|
||||
override def read(str : String) : Seq[TransactionOutput] = {
|
||||
val bytes = ScalacoinUtil.decodeHex(str)
|
||||
|
||||
val numOutputs = bytes(0).toInt
|
||||
val satoshisHex = ScalacoinUtil.encodeHex(bytes.slice(1,9))
|
||||
val satoshis = Satoshis(Integer.parseInt(satoshisHex,16))
|
||||
val scriptBytes = bytes.slice(10,bytes.size)
|
||||
val script = parse(scriptBytes)
|
||||
/*TransactionOutputImpl(satoshis, 0, script)*/
|
||||
???
|
||||
override def read(bytes : List[Byte]) : Seq[TransactionOutput] = {
|
||||
val numOutputs = bytes.head.toInt
|
||||
@tailrec
|
||||
def loop(bytes : List[Byte], accum : List[TransactionOutput], outputsLeftToParse : Int) : List[TransactionOutput] = {
|
||||
if (outputsLeftToParse > 0) {
|
||||
val satoshisHex = ScalacoinUtil.encodeHex(bytes.take(8).reverse)
|
||||
val satoshis = Satoshis(Integer.parseInt(satoshisHex, 16))
|
||||
//it doesn't include itself towards the size, thats why it is incremented by one
|
||||
val firstScriptPubKeyByte = 8
|
||||
val scriptPubKeySize = bytes(firstScriptPubKeyByte).toInt + 1
|
||||
val scriptPubKeyBytes = bytes.slice(firstScriptPubKeyByte, firstScriptPubKeyByte + scriptPubKeySize)
|
||||
val script = RawScriptPubKeyParser.read(scriptPubKeyBytes)
|
||||
val newAccum = TransactionOutputImpl(satoshis, 0, script) :: accum
|
||||
val bytesToBeParsed = bytes.slice(firstScriptPubKeyByte + scriptPubKeySize, bytes.size)
|
||||
loop(bytesToBeParsed, newAccum, outputsLeftToParse-1)
|
||||
} else accum
|
||||
}
|
||||
loop(bytes.tail,List(),numOutputs).reverse
|
||||
}
|
||||
|
||||
override def write(outputs : Seq[TransactionOutput]) : String = ???
|
||||
override def write(outputs : Seq[TransactionOutput]) : String = {
|
||||
val numOutputs = ScalacoinUtil.encodeHex(outputs.size.toByte)
|
||||
val serializedOutputs : Seq[String] = for {
|
||||
output <- outputs
|
||||
} yield {
|
||||
val satoshis = CurrencyUnits.toSatoshis(output.value)
|
||||
//TODO: Clean this up, this is very confusing. If you remove this .reverse method calls you can see the unit test failing
|
||||
val satoshisHexWithoutPadding : String =
|
||||
ScalacoinUtil.encodeHex(ScalacoinUtil.decodeHex(ScalacoinUtil.encodeHex(satoshis)).reverse).reverse
|
||||
val paddingNeeded = 16 - satoshisHexWithoutPadding.size
|
||||
val padding : Seq[String] = for ( i <- 0 until paddingNeeded) yield "0"
|
||||
val satoshisHex = padding.mkString + satoshisHexWithoutPadding
|
||||
satoshisHex.reverse + output.scriptPubKey.hex
|
||||
}
|
||||
numOutputs + serializedOutputs.mkString
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object RawTransactionOutputParser extends RawTransactionOutputParser
|
@ -16,12 +16,14 @@ class RawScriptPubKeyParserTest extends FlatSpec with MustMatchers with RawScrip
|
||||
//scriptPubKey taken from https://bitcoin.org/en/developer-reference#raw-transaction-format
|
||||
val rawScriptPubKey = "1976a914cbc20a7664f2f69e5355aa427045bc15e7c6c77288ac"
|
||||
"RawScriptPubKeyParser" must "parse a hex string into a scriptPubKey" in {
|
||||
|
||||
val scriptPubKey : ScriptPubKey = read(rawScriptPubKey)
|
||||
println(encodeBase58(decodeHex("cbc20a7664f2f69e5355aa427045bc15e7c6c772")))
|
||||
scriptPubKey.asm must be (Seq(OP_DUP,OP_HASH160,ScriptConstantImpl("cbc20a7664f2f69e5355aa427045bc15e7c6c772"),OP_EQUALVERIFY,OP_CHECKSIG))
|
||||
|
||||
|
||||
}
|
||||
|
||||
it must "read then write the scriptPubKey and get the original scriptPubKey" in {
|
||||
val scriptPubKey : ScriptPubKey = read(rawScriptPubKey)
|
||||
write(scriptPubKey) must be (rawScriptPubKey)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,19 +1,39 @@
|
||||
package org.scalacoin.marshallers.transaction
|
||||
|
||||
import org.scalacoin.marshallers.RawBitcoinSerializer
|
||||
import org.scalacoin.currency.{CurrencyUnits, Bitcoins}
|
||||
import org.scalacoin.protocol.P2SH
|
||||
import org.scalacoin.protocol.transaction.TransactionOutput
|
||||
import org.scalacoin.script.bitwise.OP_EQUAL
|
||||
import org.scalacoin.script.constant.ScriptConstantImpl
|
||||
import org.scalacoin.script.crypto.OP_HASH160
|
||||
import org.scalatest.{MustMatchers, FlatSpec}
|
||||
|
||||
/**
|
||||
* Created by chris on 1/11/16.
|
||||
* https://bitcoin.org/en/developer-reference#txout
|
||||
*/
|
||||
class RawTransactionOutputMarshallerTest extends FlatSpec with MustMatchers {
|
||||
class RawTransactionOutputMarshallerTest extends FlatSpec with MustMatchers with RawTransactionOutputParser {
|
||||
|
||||
//txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6
|
||||
val rawTxOutput = "02204e00000000000017a914eda8ae08b5c9f973f49543e90a7c292367b3337c87197d2d000000000017a914be2319b9060429692ebeffaa3be38497dc5380c887"
|
||||
val rawTxOutput = "02204e00000000000017a914eda8ae08b5c9f973f49543e90a7c292367b3337c87" +
|
||||
"197d2d000000000017a914be2319b9060429692ebeffaa3be38497dc5380c887"
|
||||
"RawTransactionOutputMarshaller" must "read a serialized tx output" in {
|
||||
|
||||
val _ : Seq[TransactionOutput] = ???
|
||||
val txOutput : Seq[TransactionOutput] = read(rawTxOutput)
|
||||
val firstOutput = txOutput.head
|
||||
val secondOutput = txOutput(1)
|
||||
firstOutput.value must be (CurrencyUnits.toSatoshis(Bitcoins(0.0002)))
|
||||
secondOutput.value must be (CurrencyUnits.toSatoshis(Bitcoins(0.02981145)))
|
||||
firstOutput.scriptPubKey.asm must be (Seq(OP_HASH160, ScriptConstantImpl("eda8ae08b5c9f973f49543e90a7c292367b3337c"), OP_EQUAL))
|
||||
secondOutput.scriptPubKey.asm must be (Seq(OP_HASH160, ScriptConstantImpl("be2319b9060429692ebeffaa3be38497dc5380c8"), OP_EQUAL))
|
||||
firstOutput.scriptPubKey.addressType must be (P2SH)
|
||||
secondOutput.scriptPubKey.addressType must be (P2SH)
|
||||
}
|
||||
|
||||
it must "seralialize a transaction output" in {
|
||||
val txOutput = read(rawTxOutput)
|
||||
|
||||
write(txOutput) must be (rawTxOutput)
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user