mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-19 09:52:09 +01:00
Seq and Map Wrappers (#1131)
* Renamed size to byteSize in NetworkElement to avoid ambiguity * Introduced SeqWrapper and MapWrapper to allow for wrapper case classes to have direct access to underlying methods * Responded to review
This commit is contained in:
parent
03cfbc0803
commit
052b64b7e2
@ -60,7 +60,7 @@ class RawTransactionRpcTest extends BitcoindRpcTest {
|
||||
} yield {
|
||||
assert(rpcTransaction.txid == transaction.txIdBE)
|
||||
assert(rpcTransaction.locktime == transaction.lockTime)
|
||||
assert(rpcTransaction.size == transaction.size)
|
||||
assert(rpcTransaction.size == transaction.byteSize)
|
||||
assert(rpcTransaction.version == transaction.version.toInt)
|
||||
assert(rpcTransaction.vsize == transaction.vsize)
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.blockchain.BlockHeader
|
||||
import org.bitcoins.core.protocol.script.ScriptPubKey
|
||||
import org.bitcoins.core.protocol.transaction.Transaction
|
||||
import org.bitcoins.core.util.SeqWrapper
|
||||
import org.bitcoins.core.wallet.fee.BitcoinFeeUnit
|
||||
import play.api.libs.json.JsObject
|
||||
|
||||
@ -161,6 +162,9 @@ case class TestMempoolAcceptResult(
|
||||
|
||||
final case class DeriveAddressesResult(addresses: Vector[BitcoinAddress])
|
||||
extends OtherResult
|
||||
with SeqWrapper[BitcoinAddress] {
|
||||
override protected val wrapped: Vector[BitcoinAddress] = addresses
|
||||
}
|
||||
|
||||
final case class GetDescriptorInfoResult(
|
||||
descriptor: String,
|
||||
|
@ -2,12 +2,11 @@ package org.bitcoins.chain.blockchain
|
||||
|
||||
import org.bitcoins.chain.models.BlockHeaderDb
|
||||
|
||||
import scala.collection.{mutable, IndexedSeqLike}
|
||||
import scala.collection.mutable
|
||||
|
||||
/** @inheritdoc */
|
||||
case class Blockchain(headers: Vector[BlockHeaderDb])
|
||||
extends IndexedSeqLike[BlockHeaderDb, Vector[BlockHeaderDb]]
|
||||
with BaseBlockChain {
|
||||
extends BaseBlockChain {
|
||||
|
||||
protected[blockchain] def compObjectfromHeaders(
|
||||
headers: scala.collection.immutable.Seq[BlockHeaderDb]): Blockchain =
|
||||
|
@ -2,20 +2,13 @@ package org.bitcoins.chain.blockchain
|
||||
|
||||
import org.bitcoins.chain.models.BlockHeaderDb
|
||||
|
||||
import scala.collection.immutable.IndexedSeq
|
||||
|
||||
/** @inheritdoc */
|
||||
case class Blockchain(headers: Vector[BlockHeaderDb])
|
||||
extends IndexedSeq[BlockHeaderDb]
|
||||
with BaseBlockChain {
|
||||
case class Blockchain(headers: Vector[BlockHeaderDb]) extends BaseBlockChain {
|
||||
|
||||
protected[blockchain] def compObjectfromHeaders(
|
||||
headers: scala.collection.immutable.Seq[BlockHeaderDb]) =
|
||||
Blockchain.fromHeaders(headers)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def seq = this
|
||||
|
||||
}
|
||||
|
||||
object Blockchain extends BaseBlockChainCompObject {
|
||||
|
@ -7,6 +7,7 @@ import org.bitcoins.chain.ChainVerificationLogger
|
||||
import org.bitcoins.chain.validation.TipUpdateResult
|
||||
import org.bitcoins.chain.validation.TipValidation
|
||||
import org.bitcoins.core.crypto.DoubleSha256DigestBE
|
||||
import org.bitcoins.core.util.SeqWrapper
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
@ -33,7 +34,7 @@ import scala.annotation.tailrec
|
||||
* }}}
|
||||
*
|
||||
*/
|
||||
private[blockchain] trait BaseBlockChain {
|
||||
private[blockchain] trait BaseBlockChain extends SeqWrapper[BlockHeaderDb] {
|
||||
|
||||
protected[blockchain] def compObjectfromHeaders(
|
||||
headers: scala.collection.immutable.Seq[BlockHeaderDb]): Blockchain
|
||||
@ -43,12 +44,10 @@ private[blockchain] trait BaseBlockChain {
|
||||
/** The height of the chain */
|
||||
val height: Int = tip.height
|
||||
|
||||
val length: Int = headers.length
|
||||
|
||||
def apply(idx: Int): BlockHeaderDb = headers(idx)
|
||||
|
||||
def headers: Vector[BlockHeaderDb]
|
||||
|
||||
override protected lazy val wrapped: Vector[BlockHeaderDb] = headers
|
||||
|
||||
def find(predicate: BlockHeaderDb => Boolean): Option[BlockHeaderDb]
|
||||
|
||||
/** Finds a block header at a given height */
|
||||
|
@ -74,8 +74,8 @@ class TransactionTest extends BitcoinSUnitTest {
|
||||
val rawTx = TestUtil.rawTransaction
|
||||
val tx = Transaction(rawTx)
|
||||
//size is in bytes so divide by 2
|
||||
assert(tx.size == tx.totalSize)
|
||||
tx.size must be(rawTx.size / 2)
|
||||
assert(tx.byteSize == tx.totalSize)
|
||||
tx.byteSize must be(rawTx.size / 2)
|
||||
}
|
||||
|
||||
it must "serialize and deserialize a tx" in {
|
||||
@ -132,7 +132,7 @@ class TransactionTest extends BitcoinSUnitTest {
|
||||
"0200000000010140d43a99926d43eb0e619bf0b3d83b4a31f60c176beecfb9d35bf45e54d0f7420100000017160014a4b4ca48de0b3fffc15404a1acdc8dbaae226955ffffffff0100e1f5050000000017a9144a1154d50b03292b3024370901711946cb7cccc387024830450221008604ef8f6d8afa892dee0f31259b6ce02dd70c545cfcfed8148179971876c54a022076d771d6e91bed212783c9b06e0de600fab2d518fad6f15a2b191d7fbd262a3e0121039d25ab79f41f75ceaf882411fd41fa670a4c672c23ffaf0e361a969cde0692e800000000"
|
||||
val tx2 = WitnessTransaction(hex2)
|
||||
tx2.hex must be(hex2)
|
||||
tx2.size must be(216)
|
||||
tx2.byteSize must be(216)
|
||||
tx2.weight must be(534)
|
||||
tx2.vsize must be(134)
|
||||
tx2.baseSize must be(106)
|
||||
|
@ -32,7 +32,7 @@ class RawTransactionInputParserTest extends FlatSpec with MustMatchers {
|
||||
|
||||
it must "find the correct size for an input" in {
|
||||
val txInput: TransactionInput = RawTransactionInputParser.read(rawTxInput)
|
||||
txInput.size must be(BitcoinSUtil.decodeHex(rawTxInput).size)
|
||||
txInput.byteSize must be(BitcoinSUtil.decodeHex(rawTxInput).size)
|
||||
}
|
||||
|
||||
it must "write a single input" in {
|
||||
|
@ -62,7 +62,7 @@ class RawTransactionOutPointParserTest extends BitcoinSUnitTest {
|
||||
val rawOutPoint =
|
||||
"85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000"
|
||||
val outPoint = RawTransactionOutPointParser.read(rawOutPoint)
|
||||
outPoint.size must be(36)
|
||||
outPoint.byteSize must be(36)
|
||||
}
|
||||
|
||||
it must "parse a outpoint with extremely large vout" in {
|
||||
|
@ -50,7 +50,7 @@ object BIP39Seed extends Factory[BIP39Seed] {
|
||||
password: String = EMPTY_PASSWORD): BIP39Seed = {
|
||||
val salt = s"mnemonic$password"
|
||||
|
||||
val words = mnemonic.words.mkString(" ")
|
||||
val words = mnemonic.mkString(" ")
|
||||
|
||||
val encodedBytes = PBKDF2
|
||||
.withSha512(words, salt, ITERATION_COUNT, DERIVED_KEY_LENGTH)
|
||||
|
@ -92,7 +92,7 @@ sealed abstract class ExtKey extends NetworkElement {
|
||||
case Nil => Success(accum)
|
||||
}
|
||||
}
|
||||
loop(path.path.toList, pub)
|
||||
loop(path.toList, pub)
|
||||
}
|
||||
|
||||
}
|
||||
@ -184,7 +184,7 @@ sealed abstract class ExtPrivateKey
|
||||
* specialized version of a BIP32 path
|
||||
*/
|
||||
def deriveChildPrivKey(path: BIP32Path): ExtPrivateKey = {
|
||||
path.path.foldLeft(this)((accum: ExtPrivateKey, curr: BIP32Node) =>
|
||||
path.foldLeft(this)((accum: ExtPrivateKey, curr: BIP32Node) =>
|
||||
accum.deriveChildPrivKey(curr.toUInt32))
|
||||
}
|
||||
|
||||
@ -326,8 +326,8 @@ object ExtPrivateKey extends Factory[ExtPrivateKey] {
|
||||
chaincode,
|
||||
masterPrivKey)
|
||||
|
||||
path.path.foldLeft(root)((accum, curr) =>
|
||||
accum.deriveChildPrivKey(curr.toUInt32))
|
||||
path.foldLeft(root)(
|
||||
(accum, curr) => accum.deriveChildPrivKey(curr.toUInt32))
|
||||
}
|
||||
|
||||
/** Generates a extended private key from the provided seed and version */
|
||||
|
@ -2,7 +2,7 @@ package org.bitcoins.core.crypto
|
||||
|
||||
import java.security.SecureRandom
|
||||
|
||||
import org.bitcoins.core.util.{CryptoUtil, MaskedToString}
|
||||
import org.bitcoins.core.util.{CryptoUtil, MaskedToString, SeqWrapper}
|
||||
import scodec.bits.{BitVector, ByteVector}
|
||||
|
||||
import scala.annotation.tailrec
|
||||
@ -16,7 +16,9 @@ import scala.io.Source
|
||||
* can be the root of a [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]]
|
||||
* HD wallet.
|
||||
*/
|
||||
sealed abstract class MnemonicCode extends MaskedToString {
|
||||
sealed abstract class MnemonicCode
|
||||
extends SeqWrapper[String]
|
||||
with MaskedToString {
|
||||
require(
|
||||
MnemonicCode.VALID_LENGTHS.contains(words.length), {
|
||||
val validLengths = MnemonicCode.VALID_LENGTHS.mkString(", ")
|
||||
@ -51,6 +53,8 @@ sealed abstract class MnemonicCode extends MaskedToString {
|
||||
*/
|
||||
def words: Vector[String]
|
||||
|
||||
override protected lazy val wrapped: Vector[String] = words
|
||||
|
||||
/**
|
||||
* Returns the entropy initially provided to construct
|
||||
* this mnemonic code
|
||||
|
@ -86,7 +86,7 @@ sealed trait WitnessTxSigComponent extends TxSigComponent {
|
||||
|
||||
override def transaction: WitnessTransaction
|
||||
|
||||
def witness: ScriptWitness = transaction.witness.witnesses(inputIndex.toInt)
|
||||
def witness: ScriptWitness = transaction.witness(inputIndex.toInt)
|
||||
|
||||
def witnessVersion: WitnessVersion
|
||||
|
||||
|
@ -2,11 +2,12 @@ package org.bitcoins.core.hd
|
||||
|
||||
import org.bitcoins.core.crypto.ExtKey
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.util.Factory
|
||||
import org.bitcoins.core.util.{Factory, SeqWrapper}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
abstract class BIP32Path {
|
||||
abstract class BIP32Path extends SeqWrapper[BIP32Node] {
|
||||
def path: Vector[BIP32Node]
|
||||
override protected lazy val wrapped: Vector[BIP32Node] = path
|
||||
|
||||
/**
|
||||
* BIP32 paths can be subsets/superset of each other.
|
||||
@ -31,12 +32,11 @@ abstract class BIP32Path {
|
||||
* m/44'/1'/0 diff m/44'/2'/1 == None
|
||||
* }}}
|
||||
*/
|
||||
def diff(that: BIP32Path): Option[BIP32Path] = {
|
||||
import that.{path => otherPath}
|
||||
def diff(otherPath: BIP32Path): Option[BIP32Path] = {
|
||||
|
||||
if (path.length > otherPath.length) {
|
||||
None
|
||||
} else if (path == otherPath) {
|
||||
} else if (this.toVector == otherPath.toVector) {
|
||||
Some(BIP32Path.empty)
|
||||
} else {
|
||||
val lengthDiff = otherPath.length - path.length
|
||||
@ -64,7 +64,7 @@ abstract class BIP32Path {
|
||||
// append the next divergent element to
|
||||
// the acummed value
|
||||
case (Some(accum), ((None, their), _)) =>
|
||||
Some(BIP32Path(accum.path :+ their))
|
||||
Some(BIP32Path((accum :+ their).toVector))
|
||||
|
||||
// we've not yet reached the start of diverging
|
||||
// paths
|
||||
|
@ -53,6 +53,6 @@ object HDAccount {
|
||||
}
|
||||
|
||||
def isSameAccount(bip32Path: BIP32Path, account: HDAccount): Boolean = {
|
||||
isSameAccount(bip32Path.path, account)
|
||||
isSameAccount(bip32Path.toVector, account)
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ sealed abstract class CompactSizeUInt extends NetworkElement {
|
||||
/** The number parsed from VarInt. */
|
||||
def num: UInt64
|
||||
|
||||
override def hex = size match {
|
||||
override def hex = byteSize match {
|
||||
case 1 => BitcoinSUtil.flipEndianness(num.hex.slice(14, 16))
|
||||
case 3 => "fd" + BitcoinSUtil.flipEndianness(num.hex.slice(12, 16))
|
||||
case 5 => "fe" + BitcoinSUtil.flipEndianness(num.hex.slice(8, 16))
|
||||
@ -37,7 +37,9 @@ sealed abstract class CompactSizeUInt extends NetworkElement {
|
||||
}
|
||||
|
||||
object CompactSizeUInt extends Factory[CompactSizeUInt] {
|
||||
private case class CompactSizeUIntImpl(num: UInt64, override val size: Long)
|
||||
private case class CompactSizeUIntImpl(
|
||||
num: UInt64,
|
||||
override val byteSize: Long)
|
||||
extends CompactSizeUInt
|
||||
|
||||
val zero: CompactSizeUInt = CompactSizeUInt(UInt64.zero)
|
||||
|
@ -11,7 +11,7 @@ import scodec.bits.ByteVector
|
||||
trait NetworkElement extends Any {
|
||||
|
||||
/** The size of the NetworkElement in bytes. */
|
||||
def size: Long = bytes.size
|
||||
def byteSize: Long = bytes.size
|
||||
|
||||
/** The hexadecimal representation of the NetworkElement */
|
||||
def hex: String = bytes.toHex
|
||||
|
@ -3,7 +3,7 @@ package org.bitcoins.core.protocol.ln
|
||||
import org.bitcoins.core.number.{UInt5, UInt8}
|
||||
import org.bitcoins.core.protocol.NetworkElement
|
||||
import org.bitcoins.core.protocol.ln.util.LnUtil
|
||||
import org.bitcoins.core.util.Bech32
|
||||
import org.bitcoins.core.util.{Bech32, SeqWrapper}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
import scala.annotation.tailrec
|
||||
@ -13,7 +13,9 @@ import scala.reflect.ClassTag
|
||||
/**
|
||||
* An aggregation of all the individual tagged fields in a [[org.bitcoins.core.protocol.ln.LnInvoice]]
|
||||
*/
|
||||
sealed abstract class LnTaggedFields extends NetworkElement {
|
||||
sealed abstract class LnTaggedFields
|
||||
extends SeqWrapper[LnTag]
|
||||
with NetworkElement {
|
||||
|
||||
require(tag[LnTag.PaymentHashTag].nonEmpty, "You must supply a payment hash")
|
||||
require(
|
||||
@ -26,6 +28,8 @@ sealed abstract class LnTaggedFields extends NetworkElement {
|
||||
|
||||
def tags: Vector[LnTag]
|
||||
|
||||
override protected lazy val wrapped: Vector[LnTag] = tags
|
||||
|
||||
def tag[T <: LnTag: ClassTag]: Option[T] =
|
||||
tags.collectFirst {
|
||||
case t: T => t
|
||||
|
@ -10,7 +10,7 @@ import org.bitcoins.core.protocol.ln.node.NodeId
|
||||
import org.bitcoins.core.protocol.ln.routing.LnRoute
|
||||
import org.bitcoins.core.protocol.ln.util.LnUtil
|
||||
import org.bitcoins.core.protocol.script.{P2WPKHWitnessSPKV0, P2WSHWitnessSPKV0}
|
||||
import org.bitcoins.core.util.{Bech32, CryptoUtil}
|
||||
import org.bitcoins.core.util.{Bech32, CryptoUtil, SeqWrapper}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
import scala.annotation.tailrec
|
||||
@ -19,7 +19,7 @@ import scala.annotation.tailrec
|
||||
* One of the tagged fields on a Lightning Network invoice
|
||||
* [[https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#tagged-fields]]
|
||||
*/
|
||||
sealed abstract class LnTag {
|
||||
sealed trait LnTag {
|
||||
|
||||
def prefix: LnTagPrefix
|
||||
|
||||
@ -217,7 +217,10 @@ object LnTag {
|
||||
}
|
||||
}
|
||||
|
||||
case class RoutingInfo(routes: Vector[LnRoute]) extends LnTag {
|
||||
case class RoutingInfo(routes: Vector[LnRoute])
|
||||
extends SeqWrapper[LnRoute]
|
||||
with LnTag {
|
||||
override protected val wrapped: Vector[LnRoute] = routes
|
||||
|
||||
override val prefix: LnTagPrefix = LnTagPrefix.RoutingInfo
|
||||
|
||||
@ -247,7 +250,7 @@ object LnTag {
|
||||
accum
|
||||
} else {
|
||||
val route = LnRoute.fromBytes(remaining)
|
||||
val newRemaining = remaining.slice(route.size, remaining.size)
|
||||
val newRemaining = remaining.slice(route.byteSize, remaining.size)
|
||||
loop(newRemaining, accum.:+(route))
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ sealed abstract class Transaction extends NetworkElement {
|
||||
* [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#Transaction_size_calculations]]
|
||||
*/
|
||||
def baseSize: Long = this match {
|
||||
case btx: BaseTransaction => btx.size
|
||||
case btx: BaseTransaction => btx.byteSize
|
||||
case wtx: WitnessTransaction =>
|
||||
BaseTransaction(wtx.version, wtx.inputs, wtx.outputs, wtx.lockTime).baseSize
|
||||
}
|
||||
@ -106,7 +106,7 @@ sealed abstract class Transaction extends NetworkElement {
|
||||
|
||||
sealed abstract class BaseTransaction extends Transaction {
|
||||
override def bytes = RawBaseTransactionParser.write(this)
|
||||
override def weight = size * 4
|
||||
override def weight = byteSize * 4
|
||||
|
||||
}
|
||||
|
||||
@ -120,8 +120,8 @@ case object EmptyTransaction extends BaseTransaction {
|
||||
|
||||
sealed abstract class WitnessTransaction extends Transaction {
|
||||
require(
|
||||
inputs.length == witness.witnesses.length,
|
||||
s"Must have same amount of inputs and witnesses in witness tx, inputs=${inputs.length} witnesses=${witness.witnesses.length}"
|
||||
inputs.length == witness.length,
|
||||
s"Must have same amount of inputs and witnesses in witness tx, inputs=${inputs.length} witnesses=${witness.length}"
|
||||
)
|
||||
|
||||
/** The txId for the witness transaction from satoshi's original serialization */
|
||||
@ -153,7 +153,7 @@ sealed abstract class WitnessTransaction extends Transaction {
|
||||
*/
|
||||
override def weight: Long = {
|
||||
val base = BaseTransaction(version, inputs, outputs, lockTime)
|
||||
base.size * 3 + size
|
||||
base.byteSize * 3 + byteSize
|
||||
}
|
||||
override def bytes = RawWitnessTransactionParser.write(this)
|
||||
|
||||
|
@ -11,7 +11,7 @@ case class TransactionOutput(value: CurrencyUnit, scriptPubKey: ScriptPubKey)
|
||||
extends NetworkElement {
|
||||
|
||||
//https://bitcoin.org/en/developer-reference#txout
|
||||
override def size = scriptPubKey.size + 8
|
||||
override def byteSize = scriptPubKey.byteSize + 8
|
||||
|
||||
override def bytes = RawTransactionOutputParser.write(this)
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package org.bitcoins.core.protocol.transaction
|
||||
import org.bitcoins.core.protocol.NetworkElement
|
||||
import org.bitcoins.core.protocol.script.{EmptyScriptWitness, ScriptWitness}
|
||||
import org.bitcoins.core.serializers.transaction.RawTransactionWitnessParser
|
||||
import org.bitcoins.core.util.BitcoinSUtil
|
||||
import org.bitcoins.core.util.{BitcoinSUtil, SeqWrapper}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
/**
|
||||
@ -11,8 +11,11 @@ import scodec.bits.ByteVector
|
||||
* The witness data for [[org.bitcoins.core.protocol.script.ScriptSignature ScriptSignature]] in this transaction
|
||||
* [[https://github.com/bitcoin/bitcoin/blob/b4e4ba475a5679e09f279aaf2a83dcf93c632bdb/src/primitives/transaction.h#L232-L268]]
|
||||
*/
|
||||
sealed abstract class TransactionWitness extends NetworkElement {
|
||||
sealed abstract class TransactionWitness
|
||||
extends SeqWrapper[ScriptWitness]
|
||||
with NetworkElement {
|
||||
val witnesses: Vector[ScriptWitness]
|
||||
override protected val wrapped: Vector[ScriptWitness] = witnesses
|
||||
|
||||
override def bytes: ByteVector = {
|
||||
RawTransactionWitnessParser.write(this)
|
||||
|
@ -387,7 +387,7 @@ case class PSBT(
|
||||
if (!previousElements.exists(_.key == expectedBytes)) {
|
||||
val fp =
|
||||
if (extKey.fingerprint == ExtKey.masterFingerprint) {
|
||||
extKey.deriveChildPubKey(path.path.head).get.fingerprint
|
||||
extKey.deriveChildPubKey(path.head).get.fingerprint
|
||||
} else {
|
||||
extKey.fingerprint
|
||||
}
|
||||
@ -579,7 +579,7 @@ case class PSBT(
|
||||
case Some(
|
||||
InputPSBTRecord.FinalizedScriptWitness(scriptWitness)) =>
|
||||
TransactionWitness(
|
||||
witness.witnesses.updated(index, scriptWitness))
|
||||
witness.updated(index, scriptWitness).toVector)
|
||||
}
|
||||
}
|
||||
WitnessTransaction(transaction.version,
|
||||
|
@ -13,7 +13,7 @@ import org.bitcoins.core.protocol.transaction.{
|
||||
WitnessTransaction
|
||||
}
|
||||
import org.bitcoins.core.script.crypto.HashType
|
||||
import org.bitcoins.core.util.{CryptoUtil, Factory}
|
||||
import org.bitcoins.core.util.{CryptoUtil, Factory, SeqWrapper}
|
||||
import org.bitcoins.core.wallet.signer.{BitcoinSigner, BitcoinSignerSingle}
|
||||
import org.bitcoins.core.wallet.utxo._
|
||||
import scodec.bits.ByteVector
|
||||
@ -87,11 +87,13 @@ sealed trait PSBTMapFactory[
|
||||
}
|
||||
|
||||
case class GlobalPSBTMap(elements: Vector[GlobalPSBTRecord])
|
||||
extends PSBTMap[GlobalPSBTRecord] {
|
||||
extends SeqWrapper[GlobalPSBTRecord]
|
||||
with PSBTMap[GlobalPSBTRecord] {
|
||||
import org.bitcoins.core.psbt.GlobalPSBTRecord._
|
||||
import org.bitcoins.core.psbt.PSBTGlobalKeyId._
|
||||
require(getRecords(UnsignedTransactionKeyId).nonEmpty,
|
||||
"A GlobalPSBTMap must have a Unsigned Transaction")
|
||||
override val wrapped: Vector[GlobalPSBTRecord] = elements
|
||||
|
||||
def unsignedTransaction: UnsignedTransaction = {
|
||||
getRecords(UnsignedTransactionKeyId).head
|
||||
@ -150,11 +152,14 @@ object GlobalPSBTMap extends PSBTMapFactory[GlobalPSBTRecord, GlobalPSBTMap] {
|
||||
}
|
||||
|
||||
case class InputPSBTMap(elements: Vector[InputPSBTRecord])
|
||||
extends PSBTMap[InputPSBTRecord] {
|
||||
extends SeqWrapper[InputPSBTRecord]
|
||||
with PSBTMap[InputPSBTRecord] {
|
||||
require(
|
||||
this.witnessUTXOOpt.isEmpty || this.nonWitnessOrUnknownUTXOOpt.isEmpty,
|
||||
"InputPSBTMap cannot have both a NonWitnessOrUnknownUTXO and a WitnessUTXO"
|
||||
)
|
||||
override protected val wrapped: Vector[InputPSBTRecord] = elements
|
||||
|
||||
import org.bitcoins.core.psbt.InputPSBTRecord._
|
||||
import org.bitcoins.core.psbt.PSBTInputKeyId._
|
||||
|
||||
@ -642,7 +647,7 @@ object InputPSBTMap extends PSBTMapFactory[InputPSBTRecord, InputPSBTMap] {
|
||||
sigComponent.transaction match {
|
||||
case _: BaseTransaction => InputPSBTMap(utxos ++ Vector(scriptSig))
|
||||
case wtx: WitnessTransaction =>
|
||||
val witness = wtx.witness.witnesses(sigComponent.inputIndex.toInt)
|
||||
val witness = wtx.witness(sigComponent.inputIndex.toInt)
|
||||
val scriptWitness = FinalizedScriptWitness(witness)
|
||||
val finalizedSigs =
|
||||
if (witness != EmptyScriptWitness) {
|
||||
@ -721,10 +726,13 @@ object InputPSBTMap extends PSBTMapFactory[InputPSBTRecord, InputPSBTMap] {
|
||||
override def recordFactory: Factory[InputPSBTRecord] = InputPSBTRecord
|
||||
}
|
||||
case class OutputPSBTMap(elements: Vector[OutputPSBTRecord])
|
||||
extends PSBTMap[OutputPSBTRecord] {
|
||||
extends SeqWrapper[OutputPSBTRecord]
|
||||
with PSBTMap[OutputPSBTRecord] {
|
||||
import org.bitcoins.core.psbt.OutputPSBTRecord._
|
||||
import org.bitcoins.core.psbt.PSBTOutputKeyId._
|
||||
|
||||
override val wrapped: Vector[OutputPSBTRecord] = elements
|
||||
|
||||
def redeemScriptOpt: Option[RedeemScript] = {
|
||||
getRecords(RedeemScriptKeyId).headOption
|
||||
}
|
||||
|
@ -39,11 +39,11 @@ object PSBTRecord {
|
||||
if (keyCmpctUInt.toLong == 0) {
|
||||
(ByteVector.empty, ByteVector.empty)
|
||||
} else {
|
||||
val key = bytes.drop(keyCmpctUInt.size).take(keyCmpctUInt.toLong)
|
||||
val valueBytes = bytes.drop(keyCmpctUInt.size + keyCmpctUInt.toLong)
|
||||
val key = bytes.drop(keyCmpctUInt.byteSize).take(keyCmpctUInt.toLong)
|
||||
val valueBytes = bytes.drop(keyCmpctUInt.byteSize + keyCmpctUInt.toLong)
|
||||
val valueCmpctUInt = CompactSizeUInt.parse(valueBytes)
|
||||
val value = valueBytes
|
||||
.drop(valueCmpctUInt.size)
|
||||
.drop(valueCmpctUInt.byteSize)
|
||||
.take(valueCmpctUInt.toLong)
|
||||
|
||||
(key, value)
|
||||
@ -74,8 +74,8 @@ object GlobalPSBTRecord extends Factory[GlobalPSBTRecord] {
|
||||
derivationPath: BIP32Path)
|
||||
extends GlobalPSBTRecord {
|
||||
require(
|
||||
derivationPath.path.length == xpub.depth.toInt,
|
||||
s"Derivation path length does not match xpubkey depth, difference: ${derivationPath.path.length - xpub.depth.toInt}"
|
||||
derivationPath.length == xpub.depth.toInt,
|
||||
s"Derivation path length does not match xpubkey depth, difference: ${derivationPath.length - xpub.depth.toInt}"
|
||||
)
|
||||
require(
|
||||
masterFingerprint.length == 4,
|
||||
@ -83,7 +83,7 @@ object GlobalPSBTRecord extends Factory[GlobalPSBTRecord] {
|
||||
|
||||
override type KeyId = XPubKeyKeyId.type
|
||||
override val key: ByteVector = ByteVector(XPubKeyKeyId.byte) ++ xpub.bytes
|
||||
override val value: ByteVector = derivationPath.path
|
||||
override val value: ByteVector = derivationPath
|
||||
.foldLeft(masterFingerprint)(_ ++ _.toUInt32.bytesLE)
|
||||
}
|
||||
|
||||
@ -155,7 +155,8 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] {
|
||||
pubKey: ECPublicKey,
|
||||
signature: ECDigitalSignature)
|
||||
extends InputPSBTRecord {
|
||||
require(pubKey.size == 33, s"pubKey must be 33 bytes, got: ${pubKey.size}")
|
||||
require(pubKey.byteSize == 33,
|
||||
s"pubKey must be 33 bytes, got: ${pubKey.byteSize}")
|
||||
|
||||
override type KeyId = PartialSignatureKeyId.type
|
||||
override val key: ByteVector = ByteVector(PartialSignatureKeyId.byte) ++ pubKey.bytes
|
||||
@ -186,12 +187,13 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] {
|
||||
masterFingerprint: ByteVector,
|
||||
path: BIP32Path)
|
||||
extends InputPSBTRecord {
|
||||
require(pubKey.size == 33, s"pubKey must be 33 bytes, got: ${pubKey.size}")
|
||||
require(pubKey.byteSize == 33,
|
||||
s"pubKey must be 33 bytes, got: ${pubKey.byteSize}")
|
||||
|
||||
override type KeyId = BIP32DerivationPathKeyId.type
|
||||
override val key: ByteVector = ByteVector(BIP32DerivationPathKeyId.byte) ++ pubKey.bytes
|
||||
override val value: ByteVector =
|
||||
path.path.foldLeft(masterFingerprint)(_ ++ _.toUInt32.bytesLE)
|
||||
path.foldLeft(masterFingerprint)(_ ++ _.toUInt32.bytesLE)
|
||||
}
|
||||
|
||||
case class FinalizedScriptSig(scriptSig: ScriptSignature)
|
||||
@ -307,12 +309,13 @@ object OutputPSBTRecord extends Factory[OutputPSBTRecord] {
|
||||
masterFingerprint: ByteVector,
|
||||
path: BIP32Path)
|
||||
extends OutputPSBTRecord {
|
||||
require(pubKey.size == 33, s"pubKey must be 33 bytes, got: ${pubKey.size}")
|
||||
require(pubKey.byteSize == 33,
|
||||
s"pubKey must be 33 bytes, got: ${pubKey.byteSize}")
|
||||
|
||||
override type KeyId = BIP32DerivationPathKeyId.type
|
||||
override val key: ByteVector = ByteVector(BIP32DerivationPathKeyId.byte) ++ pubKey.bytes
|
||||
override val value: ByteVector =
|
||||
path.path.foldLeft(masterFingerprint)(_ ++ _.toUInt32.bytesLE)
|
||||
path.foldLeft(masterFingerprint)(_ ++ _.toUInt32.bytesLE)
|
||||
}
|
||||
|
||||
case class Unknown(key: ByteVector, value: ByteVector)
|
||||
|
@ -1130,17 +1130,11 @@ sealed abstract class ScriptInterpreter extends BitcoinSLogger {
|
||||
case b: BaseTxSigComponent =>
|
||||
b.transaction match {
|
||||
case wtx: WitnessTransaction =>
|
||||
wtx.witness
|
||||
.witnesses(txSigComponent.inputIndex.toInt)
|
||||
.stack
|
||||
.nonEmpty
|
||||
wtx.witness(txSigComponent.inputIndex.toInt).stack.nonEmpty
|
||||
case _: BaseTransaction => false
|
||||
}
|
||||
case r: WitnessTxSigComponentRebuilt =>
|
||||
r.transaction.witness
|
||||
.witnesses(txSigComponent.inputIndex.toInt)
|
||||
.stack
|
||||
.nonEmpty
|
||||
r.transaction.witness(txSigComponent.inputIndex.toInt).stack.nonEmpty
|
||||
}
|
||||
|
||||
if (unexpectedWitness)
|
||||
|
@ -19,7 +19,7 @@ sealed abstract class RawSerializerHelper {
|
||||
bytes: ByteVector,
|
||||
constructor: ByteVector => T): (Seq[T], ByteVector) = {
|
||||
val count = CompactSizeUInt.parse(bytes)
|
||||
val payload = bytes.splitAt(count.size.toInt)._2
|
||||
val payload = bytes.splitAt(count.byteSize.toInt)._2
|
||||
var counter = 0
|
||||
val b = Vector.newBuilder[T]
|
||||
@tailrec
|
||||
@ -28,7 +28,7 @@ sealed abstract class RawSerializerHelper {
|
||||
remaining
|
||||
} else {
|
||||
val parsed = constructor(remaining)
|
||||
val (_, newRemaining) = remaining.splitAt(parsed.size)
|
||||
val (_, newRemaining) = remaining.splitAt(parsed.byteSize)
|
||||
|
||||
counter = counter + 1
|
||||
b.+=(parsed)
|
||||
|
@ -15,9 +15,9 @@ sealed abstract class RawBloomFilterSerializer
|
||||
|
||||
override def read(bytes: ByteVector): BloomFilter = {
|
||||
val filterSize = CompactSizeUInt.parseCompactSizeUInt(bytes)
|
||||
val filter = bytes.slice(filterSize.size.toInt,
|
||||
filterSize.size.toInt + filterSize.num.toInt)
|
||||
val hashFuncsIndex = (filterSize.size + filterSize.num.toInt).toInt
|
||||
val filter = bytes.slice(filterSize.byteSize.toInt,
|
||||
filterSize.byteSize.toInt + filterSize.num.toInt)
|
||||
val hashFuncsIndex = (filterSize.byteSize + filterSize.num.toInt).toInt
|
||||
val hashFuncs = UInt32(
|
||||
bytes.slice(hashFuncsIndex, hashFuncsIndex + 4).reverse)
|
||||
val tweakIndex = hashFuncsIndex + 4
|
||||
|
@ -16,7 +16,7 @@ trait RawAddrMessageSerializer extends RawBitcoinSerializer[AddrMessage] {
|
||||
|
||||
override def read(bytes: ByteVector): AddrMessage = {
|
||||
val ipCount = CompactSizeUInt.parseCompactSizeUInt(bytes)
|
||||
val ipAddressBytes = bytes.slice(ipCount.size.toInt, bytes.size)
|
||||
val ipAddressBytes = bytes.slice(ipCount.byteSize.toInt, bytes.size)
|
||||
val (networkIpAddresses, _) =
|
||||
parseNetworkIpAddresses(ipCount, ipAddressBytes)
|
||||
AddrMessage(ipCount, networkIpAddresses)
|
||||
@ -48,7 +48,7 @@ trait RawAddrMessageSerializer extends RawBitcoinSerializer[AddrMessage] {
|
||||
val networkIpAddress =
|
||||
RawNetworkIpAddressSerializer.read(remainingBytes)
|
||||
val newRemainingBytes =
|
||||
remainingBytes.slice(networkIpAddress.size, remainingBytes.size)
|
||||
remainingBytes.slice(networkIpAddress.byteSize, remainingBytes.size)
|
||||
loop(remainingAddresses - 1,
|
||||
newRemainingBytes,
|
||||
networkIpAddress :: accum)
|
||||
|
@ -14,7 +14,7 @@ trait RawFilterAddMessageSerializer
|
||||
|
||||
override def read(bytes: ByteVector): FilterAddMessage = {
|
||||
val elementSize = CompactSizeUInt.parseCompactSizeUInt(bytes)
|
||||
val element = bytes.slice(elementSize.size.toInt, bytes.size)
|
||||
val element = bytes.slice(elementSize.byteSize.toInt, bytes.size)
|
||||
FilterAddMessage(elementSize, element)
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ trait RawGetBlocksMessageSerializer
|
||||
val version = ProtocolVersion(bytes.take(4))
|
||||
val hashCount =
|
||||
CompactSizeUInt.parseCompactSizeUInt(bytes.slice(4, bytes.size))
|
||||
val blockHeaderStartByte = (hashCount.size + 4).toInt
|
||||
val blockHeaderStartByte = (hashCount.byteSize + 4).toInt
|
||||
val blockHeaderBytesStopHash = bytes.slice(blockHeaderStartByte, bytes.size)
|
||||
val (blockHashHeaders, remainingBytes) =
|
||||
parseBlockHeaders(blockHeaderBytesStopHash, hashCount)
|
||||
|
@ -15,7 +15,7 @@ trait RawGetHeadersMessageSerializer
|
||||
val version = ProtocolVersion(bytes.take(4))
|
||||
val hashCount =
|
||||
CompactSizeUInt.parseCompactSizeUInt(bytes.slice(4, bytes.length))
|
||||
val hashesStartIndex = (hashCount.size + 4).toInt
|
||||
val hashesStartIndex = (hashCount.byteSize + 4).toInt
|
||||
val (hashes, remainingBytes) =
|
||||
parseHashes(bytes.slice(hashesStartIndex, bytes.length), hashCount)
|
||||
val hashStop = DoubleSha256Digest(remainingBytes.take(32))
|
||||
|
@ -12,7 +12,7 @@ trait RawHeadersMessageSerializer extends RawBitcoinSerializer[HeadersMessage] {
|
||||
|
||||
def read(bytes: ByteVector): HeadersMessage = {
|
||||
val compactSizeUInt = CompactSizeUInt.parseCompactSizeUInt(bytes)
|
||||
val headerStartIndex = compactSizeUInt.size.toInt
|
||||
val headerStartIndex = compactSizeUInt.byteSize.toInt
|
||||
val headerBytes = bytes.slice(headerStartIndex, bytes.length)
|
||||
val headers = parseBlockHeaders(headerBytes, compactSizeUInt)
|
||||
HeadersMessage(compactSizeUInt, headers)
|
||||
|
@ -19,7 +19,7 @@ trait RawInventoryMessageSerializer
|
||||
*/
|
||||
override def read(bytes: ByteVector): InventoryMessage = {
|
||||
val inventoryCount = CompactSizeUInt.parseCompactSizeUInt(bytes)
|
||||
val inventoryStart = inventoryCount.size.toInt
|
||||
val inventoryStart = inventoryCount.byteSize.toInt
|
||||
val remainingBytes = bytes.slice(inventoryStart, bytes.size)
|
||||
val (inventories, _) = parseInventories(remainingBytes, inventoryCount)
|
||||
InventoryMessage(inventoryCount, inventories)
|
||||
|
@ -11,24 +11,24 @@ trait RawRejectMessageSerializer extends RawBitcoinSerializer[RejectMessage] {
|
||||
def read(bytes: ByteVector): RejectMessage = {
|
||||
val messageSize = CompactSizeUInt.parseCompactSizeUInt(bytes)
|
||||
val message: String = bytes
|
||||
.slice(messageSize.size.toInt,
|
||||
messageSize.size.toInt +
|
||||
.slice(messageSize.byteSize.toInt,
|
||||
messageSize.byteSize.toInt +
|
||||
messageSize.num.toInt)
|
||||
.toArray
|
||||
.map(_.toChar)
|
||||
.mkString
|
||||
val code: Char = bytes(messageSize.size.toInt + messageSize.num.toInt).toChar
|
||||
val reasonSizeStartIndex = messageSize.size.toInt + messageSize.num.toInt + 1
|
||||
val code: Char = bytes(messageSize.byteSize.toInt + messageSize.num.toInt).toChar
|
||||
val reasonSizeStartIndex = messageSize.byteSize.toInt + messageSize.num.toInt + 1
|
||||
val reasonSize = CompactSizeUInt.parseCompactSizeUInt(
|
||||
bytes.slice(reasonSizeStartIndex.toInt, bytes.size))
|
||||
val reason = bytes
|
||||
.slice(
|
||||
(reasonSizeStartIndex + reasonSize.size).toInt,
|
||||
(reasonSizeStartIndex + reasonSize.size.toInt + reasonSize.num.toInt))
|
||||
(reasonSizeStartIndex + reasonSize.byteSize).toInt,
|
||||
(reasonSizeStartIndex + reasonSize.byteSize.toInt + reasonSize.num.toInt))
|
||||
.toArray
|
||||
.map(_.toChar)
|
||||
.mkString
|
||||
val extraStartIndex = (reasonSizeStartIndex + reasonSize.size.toInt + reasonSize.num.toInt)
|
||||
val extraStartIndex = (reasonSizeStartIndex + reasonSize.byteSize.toInt + reasonSize.num.toInt)
|
||||
val extra = bytes.slice(extraStartIndex, bytes.size)
|
||||
RejectMessage(messageSize, message, code, reasonSize, reason, extra)
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ trait RawVersionMessageSerializer
|
||||
val userAgentSize =
|
||||
CompactSizeUInt.parseCompactSizeUInt(bytes.slice(80, bytes.size))
|
||||
|
||||
val userAgentBytesStartIndex = 80 + userAgentSize.size.toInt
|
||||
val userAgentBytesStartIndex = 80 + userAgentSize.byteSize.toInt
|
||||
|
||||
val userAgentBytes = bytes.slice(
|
||||
userAgentBytesStartIndex,
|
||||
|
@ -17,7 +17,7 @@ sealed abstract class RawScriptWitnessParser
|
||||
def read(bytes: ByteVector): ScriptWitness = {
|
||||
//first byte is the number of stack items
|
||||
val stackSize = CompactSizeUInt.parseCompactSizeUInt(bytes)
|
||||
val (_, stackBytes) = bytes.splitAt(stackSize.size.toInt)
|
||||
val (_, stackBytes) = bytes.splitAt(stackSize.byteSize.toInt)
|
||||
@tailrec
|
||||
def loop(
|
||||
remainingBytes: ByteVector,
|
||||
@ -27,7 +27,7 @@ sealed abstract class RawScriptWitnessParser
|
||||
else {
|
||||
val elementSize = CompactSizeUInt.parseCompactSizeUInt(remainingBytes)
|
||||
val (_, stackElementBytes) =
|
||||
remainingBytes.splitAt(elementSize.size.toInt)
|
||||
remainingBytes.splitAt(elementSize.byteSize.toInt)
|
||||
val stackElement = stackElementBytes.take(elementSize.num.toInt)
|
||||
val (_, newRemainingBytes) =
|
||||
stackElementBytes.splitAt(stackElement.size)
|
||||
|
@ -38,7 +38,7 @@ sealed abstract class RawTransactionWitnessParser {
|
||||
}
|
||||
|
||||
def write(witness: TransactionWitness): ByteVector = {
|
||||
witness.witnesses.foldLeft(ByteVector.empty)(_ ++ _.bytes)
|
||||
witness.foldLeft(ByteVector.empty)(_ ++ _.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -588,7 +588,8 @@ trait BitcoinScriptUtil extends BitcoinSLogger {
|
||||
//but scala collections don't allow you to use 'slice' with longs
|
||||
val len = Try(compactSizeUInt.num.toInt).getOrElse(Int.MaxValue)
|
||||
val scriptPubKeyBytes =
|
||||
bytes.slice(compactSizeUInt.size.toInt, len + compactSizeUInt.size.toInt)
|
||||
bytes.slice(compactSizeUInt.byteSize.toInt,
|
||||
len + compactSizeUInt.byteSize.toInt)
|
||||
val script: List[ScriptToken] = ScriptParser.fromBytes(scriptPubKeyBytes)
|
||||
f(script.toVector)
|
||||
}
|
||||
|
17
core/src/main/scala/org/bitcoins/core/util/Wrappers.scala
Normal file
17
core/src/main/scala/org/bitcoins/core/util/Wrappers.scala
Normal file
@ -0,0 +1,17 @@
|
||||
package org.bitcoins.core.util
|
||||
|
||||
trait SeqWrapper[+T] extends IndexedSeq[T] {
|
||||
protected def wrapped: IndexedSeq[T]
|
||||
override def iterator: Iterator[T] = wrapped.iterator
|
||||
override def length: Int = wrapped.length
|
||||
override def apply(idx: Int): T = wrapped(idx)
|
||||
}
|
||||
|
||||
trait MapWrapper[K, +T] extends Map[K, T] {
|
||||
protected def wrapped: Map[K, T]
|
||||
override def +[B1 >: T](kv: (K, B1)): Map[K, B1] = wrapped.+(kv)
|
||||
override def get(key: K): Option[T] = wrapped.get(key)
|
||||
override def iterator: Iterator[(K, T)] = wrapped.iterator
|
||||
override def updated[V1 >: T](key: K, value: V1): Map[K, V1] =
|
||||
wrapped.updated(key, value)
|
||||
}
|
@ -293,7 +293,7 @@ object BitcoinSignerSingle {
|
||||
btx.lockTime,
|
||||
transactionWitness)
|
||||
case wtx: WitnessTransaction =>
|
||||
wtx.witness.witnesses(inputIndex) match {
|
||||
wtx.witness(inputIndex) match {
|
||||
case EmptyScriptWitness =>
|
||||
val transactionWitnessOpt =
|
||||
psbt
|
||||
@ -740,8 +740,9 @@ sealed abstract class P2WPKHSigner
|
||||
val pubKey = signer.publicKey
|
||||
|
||||
val unsignedTxWitness = TransactionWitness(
|
||||
wtx.witness.witnesses
|
||||
.updated(inputIndex.toInt, spendingInfoToSatisfy.scriptWitness))
|
||||
wtx.witness
|
||||
.updated(inputIndex.toInt, spendingInfoToSatisfy.scriptWitness)
|
||||
.toVector)
|
||||
|
||||
val unsignedWtx = WitnessTransaction(wtx.version,
|
||||
wtx.inputs,
|
||||
|
Loading…
Reference in New Issue
Block a user