mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-26 21:42:48 +01:00
Remove the clause in Transction.fromHex() where we throw in the case … (#1431)
* Remove the clause in Transction.fromHex() where we throw in the case of a witness transaction, do something smarter and look at bytes in the byte vector * WIP add test case * Add back try/catch as it's still necessary for cases of unsigned base transactions * Add permalink to example test case
This commit is contained in:
parent
9172aa3206
commit
f3469f8e28
5 changed files with 44 additions and 25 deletions
|
@ -85,6 +85,18 @@ class TransactionTest extends BitcoinSUnitTest {
|
|||
tx.hex must be(rawTx)
|
||||
}
|
||||
|
||||
it must "deserialize and serialize a base transaction with no inputs" in {
|
||||
//this should be considered a base transaction since there is no script witnesses
|
||||
val hex = "02000000" + //version
|
||||
"0001" + //0 inputs, 1 output
|
||||
"00e1f50500000000" + //1BTC
|
||||
"17a9148fe46e05e329badba1c390a5ea2c0ad7de2059cd87" + //spk
|
||||
"00000000" //locktime
|
||||
val btx = Transaction.fromHex(hex)
|
||||
btx.isInstanceOf[BaseTransaction] must be(true)
|
||||
btx.hex must be(hex)
|
||||
}
|
||||
|
||||
it must "serialize and deserialize a large tx" in {
|
||||
val rawTx =
|
||||
"0e2fddd0071fc32e0849ef3d3f6024aa6d73fa1eb91e3daad5a5dcfde8d45a376bc2f274b207d7017e8346304402203f7973c50fa84ab8960d5895bfcc73365101cc3967fa39528a94ab5e94de218d02207d8fc26f806d26407dd13f52be1d40c90b403690cce3933f71de57607a78848a2103bf87039d25c947357b31d005575d75071ddd6e97017e9efa57559b6a5daa03af1976a9143b75df7c44a47fed51374aef67bb7e7ae071b0a788acd3f37759c999d6f325fa7fb6445a5c6989d2fcee2b60c83cc1dd167d189488f74b09eade054ef5304847304502210087ebadf23475d287824ab171addc39907f5c93d14a5b463cbcc37805cd37cdaa02206cbca1f7768e99b65bc7a03d64056f1ce8c86ab78cbc7c19d49dab2c7084f5a830204fe815b8c4937864464ade73d3869e8888569e976742b666c742e8c60a46e5e14756035ccc736946304402204c544118e309de16cde7bc69e8018688aceb0a329e935bcf5d5f6aa8904937ad022043bee0a74e0cd9a6317d2abdab6cff004a6ebff2dc3f59b75a4e90aecf83c7b32103336d83e7f45e66b6655b25a4b3ee5679785378a89a9db407360dce45b24d67e0775bfdc70000000000000000000000000000000000000000000000000000000000000000fffffffffdb20100483046022100e52e3d78998643d2987a6210972984caaf33b53e2493daaf7dda6a00c7aade80022100d92576b1a7219c49d4ae85a7e450ee039d170a7aeed5fd7b34825faaab885055473045022100977591b85fd01d0969f39bd66f84b01adf8da5879ca6fc80c474a27502d9345f02201c415141bee3504b6eb6ff08c60e1e55b519ae80191bfa2aa9f1082581d88b5a473045022100999259a53b3b692519b95f058a6a70734f77ca4752103cb777f83ff17acff4d30220383b7debacc2dec8553d73ab1d52523a56921ba3904153fb43a4509d5dff0a2b4730450220609a352f8afd4aa49fef4bd81c13df2dbae87070217958099968b652d44d40d1022100d6f9902a240a4c516479b95a4a75ee42ea31441a7163fbcfeb1879de9907d0554630440220272828412f2c0833d9328209ec476240ee8ba51453773df4639001c84657a7ed02200b75a0bc08c002be39868a596d703ce3641b243286bede8264af0df7818843cb4830460221008ead4ad119e7350ea23de18c845a2018babea3ffd135575ece8f33ebf7f6bfe5022100e5e4067b788887edec933e7776799fe2d92915cb19e21cf7145fe4577b4eb469ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff6946304402207b1000f0aea3a8f9f3952d13a7fd5eceb3740e6a4f2543987329f1a99a0bec6c0220457fcff820bac0c0f5c65c4228b89eadd380a98a99dfa2ed7c135617323b7ff021020610f065313942890798946ed97ca12d2852f66765bfd6785f90db650bb7d62affffffff42c761d25e0f10cfc2c82280f741e63e0aa184dd28627c487d6add381949be757d48ab4e85483046022100bceb7174237d148d3be472ad2fa9b19d2db5e9256943f32ed4abc6ae603602d8022100832b11ae88981e588daa6e65fcdd732ee186c21287589f7cbf0678109c483add210325259fd900969d3c16e870eeb9ecfd2bff8519c2aa81958a8bc19be6594a2d6e1976a9140bc44e1f010f5dfa4a102319e3a2445c164ce5d088ac5b0ddd9c652982074e88b4724293e21f651804b327586396ecf411784e80f6478fb23f606d569c746a47304502200ec20fae608b985e8b65f29a9e69ec671926eb837797763bf0178a515407b28a022100a131250b8be7fb2a533d44a1acf620155cf352ba8387f4e419b5b06c2b50901d2103d46e46269fc7ed661e4c34f714cfe6cd36231a77d79b7fd17edcb1741fdab9b781b905f5003c4edbe4"
|
||||
|
|
|
@ -2,21 +2,10 @@ package org.bitcoins.core.protocol.transaction
|
|||
|
||||
import org.bitcoins.core.number.{Int32, UInt32}
|
||||
import org.bitcoins.core.protocol.script.ScriptWitness
|
||||
import org.bitcoins.core.serializers.transaction.{
|
||||
RawBaseTransactionParser,
|
||||
RawWitnessTransactionParser
|
||||
}
|
||||
import org.bitcoins.crypto.{
|
||||
CryptoUtil,
|
||||
DoubleSha256Digest,
|
||||
DoubleSha256DigestBE,
|
||||
Factory,
|
||||
NetworkElement
|
||||
}
|
||||
import org.bitcoins.core.serializers.transaction.{RawBaseTransactionParser, RawWitnessTransactionParser}
|
||||
import org.bitcoins.crypto._
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
||||
/**
|
||||
* Created by chris on 7/14/15.
|
||||
*/
|
||||
|
@ -159,7 +148,7 @@ sealed abstract class WitnessTransaction extends Transaction {
|
|||
val base = BaseTransaction(version, inputs, outputs, lockTime)
|
||||
base.byteSize * 3 + byteSize
|
||||
}
|
||||
override def bytes = RawWitnessTransactionParser.write(this)
|
||||
override def bytes: ByteVector = RawWitnessTransactionParser.write(this)
|
||||
|
||||
/**
|
||||
* Updates the [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] at the given index and
|
||||
|
@ -175,14 +164,23 @@ sealed abstract class WitnessTransaction extends Transaction {
|
|||
|
||||
object Transaction extends Factory[Transaction] {
|
||||
|
||||
def fromBytes(bytes: ByteVector): Transaction = {
|
||||
val wtxTry = Try(RawWitnessTransactionParser.read(bytes))
|
||||
wtxTry match {
|
||||
case Success(wtx) =>
|
||||
wtx
|
||||
case Failure(_) =>
|
||||
val btx = RawBaseTransactionParser.read(bytes)
|
||||
btx
|
||||
override def fromBytes(bytes: ByteVector): Transaction = {
|
||||
//see BIP141 for marker/flag bytes
|
||||
//https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#transaction-id
|
||||
if (bytes(4) == WitnessTransaction.marker && bytes(5) == WitnessTransaction.flag) {
|
||||
//this throw/catch is _still_ necessary for the case where we have unsigned base transactions
|
||||
//with zero inputs and 1 output which is serialized as "0001" at bytes 4 and 5.
|
||||
//these transactions will not have a script witness associated with them making them invalid
|
||||
//witness transactions (you need to have a witness to be considered a witness tx)
|
||||
//see: https://github.com/bitcoin-s/bitcoin-s/blob/01d89df1b7c6bc4b1594406d54d5e6019705c654/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionTest.scala#L88
|
||||
try {
|
||||
RawWitnessTransactionParser.read(bytes)
|
||||
} catch {
|
||||
case scala.util.control.NonFatal(_) =>
|
||||
RawBaseTransactionParser.read(bytes)
|
||||
}
|
||||
} else {
|
||||
RawBaseTransactionParser.read(bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -235,4 +233,12 @@ object WitnessTransaction extends Factory[WitnessTransaction] {
|
|||
EmptyWitness.fromInputs(btx.inputs))
|
||||
case wtx: WitnessTransaction => wtx
|
||||
}
|
||||
|
||||
val marker: Byte = 0.toByte
|
||||
val flag: Byte = 1.toByte
|
||||
|
||||
/** These bytes -- at index 4 & 5 in a witness transaction -- are used to indicate a witness tx
|
||||
* @see BIP141 https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#transaction-id
|
||||
* */
|
||||
val witBytes: ByteVector = ByteVector(marker, flag)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.bitcoins.core.serializers
|
||||
|
||||
import org.bitcoins.core.util.BitcoinSLogger
|
||||
import org.bitcoins.crypto.BytesUtil
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
|
@ -7,7 +8,7 @@ import scodec.bits.ByteVector
|
|||
* Created by chris on 1/11/16.
|
||||
* A common trait for reading/writing bitcoin objects to/from bytes/hex
|
||||
*/
|
||||
abstract class RawBitcoinSerializer[T] {
|
||||
abstract class RawBitcoinSerializer[T] extends BitcoinSLogger {
|
||||
|
||||
/** Reads a hexadecimal value and transforms it into the native scala type T. */
|
||||
def read(hex: String): T = read(BytesUtil.decodeHex(hex))
|
||||
|
|
|
@ -20,7 +20,7 @@ sealed abstract class RawSerializerHelper {
|
|||
bytes: ByteVector,
|
||||
constructor: ByteVector => T): (Seq[T], ByteVector) = {
|
||||
val count = CompactSizeUInt.parse(bytes)
|
||||
val payload = bytes.splitAt(count.byteSize.toInt)._2
|
||||
val (_,payload) = bytes.splitAt(count.byteSize.toInt)
|
||||
var counter = 0
|
||||
val b = Vector.newBuilder[T]
|
||||
@tailrec
|
||||
|
|
|
@ -68,7 +68,7 @@ sealed abstract class RawWitnessTransactionParser
|
|||
//notice we use the old serialization format if all witnesses are empty
|
||||
// https://github.com/bitcoin/bitcoin/blob/e8cfe1ee2d01c493b758a67ad14707dca15792ea/src/primitives/transaction.h#L276-L281
|
||||
if (tx.witness.exists(_ != EmptyScriptWitness)) {
|
||||
val witConstant = ByteVector(0.toByte, 1.toByte)
|
||||
val witConstant = WitnessTransaction.witBytes
|
||||
version ++ witConstant ++ inputs ++ outputs ++ witness ++ lockTime
|
||||
} else BaseTransaction(tx.version, tx.inputs, tx.outputs, tx.lockTime).bytes
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue