Apply string factory to a bunch of easy things (#1891)

* Apply string factory to a bunch of easy things

* Refactor HDPath, ExtKey, and LnTagPrefix to use StringFactory

* Implemen StringFactory on LnHumanReadablePart, ScriptType, ServiceIdentifier

* Implement StringFactory on AesCrypt, NodeUri, AddressTag, PSBT, TxoState

* Fix failing tests, fix website compile

* Apply StringFactory to all ScriptOperations, ChannelState, Script Parsing
This commit is contained in:
Chris Stewart 2020-08-25 10:48:37 -05:00 committed by GitHub
parent 2252dc528e
commit 955978f635
54 changed files with 358 additions and 231 deletions

View file

@ -20,7 +20,8 @@ import org.bitcoins.crypto.{
DoubleSha256Digest, DoubleSha256Digest,
DoubleSha256DigestBE, DoubleSha256DigestBE,
ECDigitalSignature, ECDigitalSignature,
Sha256Digest Sha256Digest,
StringFactory
} }
import play.api.libs.json.JsObject import play.api.libs.json.JsObject
@ -48,17 +49,18 @@ case class PeerInfo(
case class ChannelCommandResult( case class ChannelCommandResult(
results: scala.collection.Map[ results: scala.collection.Map[
Either[ShortChannelId, FundedChannelId], Either[ShortChannelId, FundedChannelId],
ChannelCommandResult.State] State]
) )
sealed trait State
object ChannelCommandResult extends StringFactory[State] {
object ChannelCommandResult {
sealed trait State
case object OK extends State case object OK extends State
case object ChannelOpened extends State case object ChannelOpened extends State
case object ChannelClosed extends State case object ChannelClosed extends State
case class Error(message: String) extends State case class Error(message: String) extends State
def fromString(s: String): State = override def fromString(s: String): State =
if (s == "ok") { if (s == "ok") {
ChannelCommandResult.OK ChannelCommandResult.OK
} else if (s.startsWith("created channel ")) { } else if (s.startsWith("created channel ")) {
@ -161,9 +163,9 @@ object ChannelStats {
case object In extends Direction case object In extends Direction
case object Out extends Direction case object Out extends Direction
object Direction { object Direction extends StringFactory[Direction] {
def fromString(s: String): Direction = override def fromString(s: String): Direction =
if (s.toUpperCase == "IN") { if (s.toUpperCase == "IN") {
ChannelStats.In ChannelStats.In
} else if (s.toUpperCase == "OUT") { } else if (s.toUpperCase == "OUT") {
@ -279,13 +281,13 @@ case class PaymentRequest(
sealed trait PaymentType sealed trait PaymentType
object PaymentType { object PaymentType extends StringFactory[PaymentType] {
case object Standard extends PaymentType case object Standard extends PaymentType
case object SwapIn extends PaymentType case object SwapIn extends PaymentType
case object SwapOut extends PaymentType case object SwapOut extends PaymentType
def fromString(str: String): PaymentType = override def fromString(str: String): PaymentType =
str match { str match {
case "Standard" => Standard case "Standard" => Standard
case "SwapIn" => SwapIn case "SwapIn" => SwapIn

View file

@ -579,7 +579,7 @@ object JsonReaders {
override def reads(json: JsValue): JsResult[ScriptType] = override def reads(json: JsValue): JsResult[ScriptType] =
json json
.validate[String] .validate[String]
.map(ScriptType.fromStringExn) .map(ScriptType.fromString)
} }
implicit object TestMempoolAcceptResultReads implicit object TestMempoolAcceptResultReads
@ -649,7 +649,7 @@ object JsonReaders {
implicit val channelStateReads: Reads[ChannelState] = { implicit val channelStateReads: Reads[ChannelState] = {
Reads { jsValue: JsValue => Reads { jsValue: JsValue =>
SerializerUtil.processJsStringOpt(ChannelState.fromString)(jsValue) SerializerUtil.processJsStringOpt(ChannelState.fromStringOpt)(jsValue)
} }
} }
@ -691,8 +691,8 @@ object JsonReaders {
implicit val lnHrpReads: Reads[LnHumanReadablePart] = { implicit val lnHrpReads: Reads[LnHumanReadablePart] = {
Reads { jsValue => Reads { jsValue =>
SerializerUtil.processJsStringOpt( SerializerUtil.processJsStringOpt(LnHumanReadablePart.fromStringOpt(_))(
LnHumanReadablePart.fromString(_).toOption)(jsValue) jsValue)
} }
} }
@ -878,8 +878,7 @@ object JsonReaders {
} }
} }
implicit val channelCommandResultStateReads: Reads[ implicit val channelCommandResultStateReads: Reads[State] = Reads { jsValue =>
ChannelCommandResult.State] = Reads { jsValue =>
SerializerUtil.processJsString(ChannelCommandResult.fromString)(jsValue) SerializerUtil.processJsString(ChannelCommandResult.fromString)(jsValue)
} }
@ -890,7 +889,7 @@ object JsonReaders {
case Success(id) => Right(id) case Success(id) => Right(id)
case Failure(_) => Left(ShortChannelId.fromHumanReadableString(x._1)) case Failure(_) => Left(ShortChannelId.fromHumanReadableString(x._1))
} }
(channelId, x._2.validate[ChannelCommandResult.State].get) (channelId, x._2.validate[State].get)
})) }))
case err @ (JsNull | _: JsBoolean | _: JsString | _: JsArray | case err @ (JsNull | _: JsBoolean | _: JsString | _: JsArray |
_: JsNumber) => _: JsNumber) =>

View file

@ -97,8 +97,7 @@ object JsonSerializers {
implicit val xpubFormat: Format[ExtPublicKey] = new Format[ExtPublicKey] { implicit val xpubFormat: Format[ExtPublicKey] = new Format[ExtPublicKey] {
override def reads(json: JsValue): JsResult[ExtPublicKey] = override def reads(json: JsValue): JsResult[ExtPublicKey] =
SerializerUtil.processJsStringOpt(ExtPublicKey.fromString(_).toOption)( SerializerUtil.processJsStringOpt(ExtPublicKey.fromStringOpt(_))(json)
json)
override def writes(key: ExtPublicKey): JsValue = JsString(key.toString) override def writes(key: ExtPublicKey): JsValue = JsString(key.toString)
} }
@ -106,8 +105,7 @@ object JsonSerializers {
implicit val xprivForamt: Format[ExtPrivateKey] = new Format[ExtPrivateKey] { implicit val xprivForamt: Format[ExtPrivateKey] = new Format[ExtPrivateKey] {
override def reads(json: JsValue): JsResult[ExtPrivateKey] = override def reads(json: JsValue): JsResult[ExtPrivateKey] =
SerializerUtil.processJsStringOpt(ExtPrivateKey.fromString(_).toOption)( SerializerUtil.processJsStringOpt(ExtPrivateKey.fromStringOpt(_))(json)
json)
override def writes(key: ExtPrivateKey): JsValue = JsString(key.toString) override def writes(key: ExtPrivateKey): JsValue = JsString(key.toString)
} }

View file

@ -20,7 +20,7 @@ object Picklers {
implicit val bitcoinAddressPickler: ReadWriter[BitcoinAddress] = implicit val bitcoinAddressPickler: ReadWriter[BitcoinAddress] =
readwriter[String] readwriter[String]
.bimap(_.value, BitcoinAddress.fromStringExn) .bimap(_.value, BitcoinAddress.fromString)
implicit val bitcoinsPickler: ReadWriter[Bitcoins] = implicit val bitcoinsPickler: ReadWriter[Bitcoins] =
readwriter[Double].bimap(_.toBigDecimal.toDouble, Bitcoins(_)) readwriter[Double].bimap(_.toBigDecimal.toDouble, Bitcoins(_))
@ -82,13 +82,13 @@ object Picklers {
readwriter[String].bimap(_.hex, Transaction.fromHex) readwriter[String].bimap(_.hex, Transaction.fromHex)
implicit val extPubKeyPickler: ReadWriter[ExtPublicKey] = implicit val extPubKeyPickler: ReadWriter[ExtPublicKey] =
readwriter[String].bimap(_.toString, ExtPublicKey.fromString(_).get) readwriter[String].bimap(_.toString, ExtPublicKey.fromString(_))
implicit val transactionOutPointPickler: ReadWriter[TransactionOutPoint] = implicit val transactionOutPointPickler: ReadWriter[TransactionOutPoint] =
readwriter[String].bimap(_.hex, TransactionOutPoint.fromHex) readwriter[String].bimap(_.hex, TransactionOutPoint.fromHex)
implicit val coinSelectionAlgoPickler: ReadWriter[CoinSelectionAlgo] = implicit val coinSelectionAlgoPickler: ReadWriter[CoinSelectionAlgo] =
readwriter[String].bimap(_.toString, CoinSelectionAlgo.fromString(_).get) readwriter[String].bimap(_.toString, CoinSelectionAlgo.fromString(_))
implicit val addressLabelTagPickler: ReadWriter[AddressLabelTag] = implicit val addressLabelTagPickler: ReadWriter[AddressLabelTag] =
readwriter[String].bimap(_.name, AddressLabelTag) readwriter[String].bimap(_.name, AddressLabelTag)

View file

@ -42,7 +42,7 @@ object CliReaders {
new Read[BitcoinAddress] { new Read[BitcoinAddress] {
val arity: Int = 1 val arity: Int = 1
val reads: String => BitcoinAddress = BitcoinAddress.fromStringExn val reads: String => BitcoinAddress = BitcoinAddress.fromString
} }
implicit val bitcoinsReads: Read[Bitcoins] = implicit val bitcoinsReads: Read[Bitcoins] =
@ -129,7 +129,7 @@ object CliReaders {
val arity: Int = 1 val arity: Int = 1
val reads: String => CoinSelectionAlgo = val reads: String => CoinSelectionAlgo =
CoinSelectionAlgo.fromString(_).get CoinSelectionAlgo.fromString(_)
} }
implicit val schnorrSigReads: Read[SchnorrDigitalSignature] = implicit val schnorrSigReads: Read[SchnorrDigitalSignature] =

View file

@ -436,7 +436,6 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
val xpub = ExtPublicKey val xpub = ExtPublicKey
.fromString( .fromString(
"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8") "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8")
.get
val accountDb = val accountDb =
AccountDb(xpub = xpub, AccountDb(xpub = xpub,
@ -477,7 +476,7 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
"get address info" in { "get address info" in {
val key = ECPublicKey.freshPublicKey val key = ECPublicKey.freshPublicKey
val hdPath = HDPath.fromString("m/84'/1'/0'/0/0").get val hdPath = HDPath.fromString("m/84'/1'/0'/0/0")
(mockWalletApi (mockWalletApi
.getAddressInfo(_: BitcoinAddress)) .getAddressInfo(_: BitcoinAddress))

View file

@ -466,7 +466,7 @@ trait ServerJsonModels {
def jsToBitcoinAddress(js: Value): BitcoinAddress = { def jsToBitcoinAddress(js: Value): BitcoinAddress = {
try { try {
BitcoinAddress.fromStringExn(js.str) BitcoinAddress.fromString(js.str)
} catch { } catch {
case _: IllegalArgumentException => case _: IllegalArgumentException =>
throw Value.InvalidData(js, "Expected a valid address") throw Value.InvalidData(js, "Expected a valid address")
@ -490,8 +490,6 @@ trait ServerJsonModels {
def jsToCoinSelectionAlgo(js: Value): CoinSelectionAlgo = def jsToCoinSelectionAlgo(js: Value): CoinSelectionAlgo =
CoinSelectionAlgo CoinSelectionAlgo
.fromString(js.str) .fromString(js.str)
.getOrElse(
throw new IllegalArgumentException("Invalid CoinSelectionAlgo"))
def jsToTx(js: Value): Transaction = Transaction.fromHex(js.str) def jsToTx(js: Value): Transaction = Transaction.fromHex(js.str)

View file

@ -18,7 +18,7 @@ class ExtKeySpec extends BitcoinSUnitTest {
it must "have serialization symmetry" in { it must "have serialization symmetry" in {
Prop.forAll(CryptoGenerators.extKey) { extKey => Prop.forAll(CryptoGenerators.extKey) { extKey =>
ExtKey.fromString(extKey.toString) == Success(extKey) && ExtKey.fromStringT(extKey.toString) == Success(extKey) &&
ExtKey(extKey.bytes) == extKey ExtKey(extKey.bytes) == extKey
} }
} }

View file

@ -43,7 +43,7 @@ class ExtKeyTest extends BitcoinSUnitTest {
it must "fail to make a private key out of a public key" in { it must "fail to make a private key out of a public key" in {
forAll(CryptoGenerators.extPublicKey) { pub => forAll(CryptoGenerators.extPublicKey) { pub =>
val attempt = ExtPrivateKey.fromString(pub.toString) val attempt = ExtPrivateKey.fromStringT(pub.toString)
attempt match { attempt match {
case Success(_) => fail case Success(_) => fail
case Failure(exc) => assert(exc.getMessage.contains("expected private")) case Failure(exc) => assert(exc.getMessage.contains("expected private"))
@ -237,7 +237,7 @@ class ExtKeyTest extends BitcoinSUnitTest {
//actual priv key 68e5ed2b2c8fc5a6605107d29d074e3d6ccb119c2811007e32f48305176f814c //actual priv key 68e5ed2b2c8fc5a6605107d29d074e3d6ccb119c2811007e32f48305176f814c
val str = val str =
"xprv9s21ZrQH143K4LCRq4tUZUt3fiTNZr6QTiep3HGzMxtSwfxKAhBmNJJnsmoyWuYZCPC4DNsiVwToHJbxZtq4iEkozBhMzWNTiCH4tzJNjPi" "xprv9s21ZrQH143K4LCRq4tUZUt3fiTNZr6QTiep3HGzMxtSwfxKAhBmNJJnsmoyWuYZCPC4DNsiVwToHJbxZtq4iEkozBhMzWNTiCH4tzJNjPi"
val masterPriv = ExtPrivateKey.fromString(str).get val masterPriv = ExtPrivateKey.fromString(str)
val idx = UInt32((1L << 31) - 1) val idx = UInt32((1L << 31) - 1)
val path1 = masterPriv.deriveChildPrivKey(idx).extPublicKey.key val path1 = masterPriv.deriveChildPrivKey(idx).extPublicKey.key
val path2 = masterPriv.extPublicKey.deriveChildPubKey(idx).get.key val path2 = masterPriv.extPublicKey.deriveChildPubKey(idx).get.key

View file

@ -220,7 +220,7 @@ class MnemonicCodeTest extends BitcoinSUnitTest {
entropy = ByteVector.fromValidHex(rawEntropy), entropy = ByteVector.fromValidHex(rawEntropy),
expectedWords = rawWords.split(" ").toVector, expectedWords = rawWords.split(" ").toVector,
expectedSeed = BIP39Seed.fromHex(rawSeed), expectedSeed = BIP39Seed.fromHex(rawSeed),
expectedXPriv = ExtPrivateKey.fromString(rawXpriv).get expectedXPriv = ExtPrivateKey.fromString(rawXpriv)
) )
} }

View file

@ -98,7 +98,7 @@ class HDPathTest extends BitcoinSUnitTest {
it must "have toString/fromString symmetry" in { it must "have toString/fromString symmetry" in {
forAll(HDGenerators.hdPath) { path => forAll(HDGenerators.hdPath) { path =>
val pathFromString = HDPath.fromString(path.toString) val pathFromString = HDPath.fromStringOpt(path.toString)
val resultOpt = pathFromString.map { val resultOpt = pathFromString.map {
case value: LegacyHDPath => case value: LegacyHDPath =>
assert(value == path.asInstanceOf[LegacyHDPath]) assert(value == path.asInstanceOf[LegacyHDPath])
@ -119,7 +119,7 @@ class HDPathTest extends BitcoinSUnitTest {
} }
forAll(badPaths) { badPath => forAll(badPaths) { badPath =>
val attempt = HDPath.fromString(badPath.toString) val attempt = HDPath.fromStringOpt(badPath.toString)
attempt match { attempt match {
case None => case None =>
succeed succeed
@ -214,7 +214,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(first.account.index == 0) assert(first.account.index == 0)
assert(first.chain.chainType == HDChainType.External) assert(first.chain.chainType == HDChainType.External)
assert(first.address.index == 0) assert(first.address.index == 0)
assert(HDPath.fromString(firstString).contains(first)) assert(HDPath.fromStringOpt(firstString).contains(first))
val secondString = " m / 44' / 0' / 0' / 0 / 1 " val secondString = " m / 44' / 0' / 0' / 0 / 1 "
val second = LegacyHDPath.fromString(secondString) val second = LegacyHDPath.fromString(secondString)
@ -223,7 +223,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(second.account.index == 0) assert(second.account.index == 0)
assert(second.chain.chainType == HDChainType.External) assert(second.chain.chainType == HDChainType.External)
assert(second.address.index == 1) assert(second.address.index == 1)
assert(HDPath.fromString(secondString).contains(second)) assert(HDPath.fromStringOpt(secondString).contains(second))
val thirdString = " m / 44' / 0' / 0' / 1 / 0 " val thirdString = " m / 44' / 0' / 0' / 1 / 0 "
val third = LegacyHDPath.fromString(thirdString) val third = LegacyHDPath.fromString(thirdString)
@ -232,7 +232,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(third.account.index == 0) assert(third.account.index == 0)
assert(third.chain.chainType == HDChainType.Change) assert(third.chain.chainType == HDChainType.Change)
assert(third.address.index == 0) assert(third.address.index == 0)
assert(HDPath.fromString(thirdString).contains(third)) assert(HDPath.fromStringOpt(thirdString).contains(third))
val fourthString = " m / 44' / 0' / 0' / 1 / 1 " val fourthString = " m / 44' / 0' / 0' / 1 / 1 "
val fourth = LegacyHDPath.fromString(fourthString) val fourth = LegacyHDPath.fromString(fourthString)
@ -241,7 +241,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(fourth.account.index == 0) assert(fourth.account.index == 0)
assert(fourth.chain.chainType == HDChainType.Change) assert(fourth.chain.chainType == HDChainType.Change)
assert(fourth.address.index == 1) assert(fourth.address.index == 1)
assert(HDPath.fromString(fourthString).contains(fourth)) assert(HDPath.fromStringOpt(fourthString).contains(fourth))
val fifthString = " m / 44' / 0' / 1' / 0 / 0 " val fifthString = " m / 44' / 0' / 1' / 0 / 0 "
val fifth = LegacyHDPath.fromString(fifthString) val fifth = LegacyHDPath.fromString(fifthString)
@ -250,7 +250,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(fifth.account.index == 1) assert(fifth.account.index == 1)
assert(fifth.chain.chainType == HDChainType.External) assert(fifth.chain.chainType == HDChainType.External)
assert(fifth.address.index == 0) assert(fifth.address.index == 0)
assert(HDPath.fromString(fifthString).contains(fifth)) assert(HDPath.fromStringOpt(fifthString).contains(fifth))
val sixthString = " m / 44' / 0' / 1' / 0 / 1 " val sixthString = " m / 44' / 0' / 1' / 0 / 1 "
val sixth = LegacyHDPath.fromString(sixthString) val sixth = LegacyHDPath.fromString(sixthString)
@ -259,7 +259,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(sixth.account.index == 1) assert(sixth.account.index == 1)
assert(sixth.chain.chainType == HDChainType.External) assert(sixth.chain.chainType == HDChainType.External)
assert(sixth.address.index == 1) assert(sixth.address.index == 1)
assert(HDPath.fromString(sixthString).contains(sixth)) assert(HDPath.fromStringOpt(sixthString).contains(sixth))
val seventhString = " m / 44' / 0' / 1' / 1 / 0 " val seventhString = " m / 44' / 0' / 1' / 1 / 0 "
val seventh = LegacyHDPath.fromString(seventhString) val seventh = LegacyHDPath.fromString(seventhString)
@ -268,7 +268,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(seventh.account.index == 1) assert(seventh.account.index == 1)
assert(seventh.chain.chainType == HDChainType.Change) assert(seventh.chain.chainType == HDChainType.Change)
assert(seventh.address.index == 0) assert(seventh.address.index == 0)
assert(HDPath.fromString(seventhString).contains(seventh)) assert(HDPath.fromStringOpt(seventhString).contains(seventh))
val eightString = " m / 44' / 0' / 1' / 1 / 1 " val eightString = " m / 44' / 0' / 1' / 1 / 1 "
val eigth = LegacyHDPath.fromString(eightString) val eigth = LegacyHDPath.fromString(eightString)
@ -277,7 +277,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(eigth.account.index == 1) assert(eigth.account.index == 1)
assert(eigth.chain.chainType == HDChainType.Change) assert(eigth.chain.chainType == HDChainType.Change)
assert(eigth.address.index == 1) assert(eigth.address.index == 1)
assert(HDPath.fromString(eightString).contains(eigth)) assert(HDPath.fromStringOpt(eightString).contains(eigth))
val ninthString = " m / 44' / 1' / 0' / 0 / 1 " val ninthString = " m / 44' / 1' / 0' / 0 / 1 "
val ninth = LegacyHDPath.fromString(ninthString) val ninth = LegacyHDPath.fromString(ninthString)
@ -286,7 +286,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(ninth.account.index == 0) assert(ninth.account.index == 0)
assert(ninth.chain.chainType == HDChainType.External) assert(ninth.chain.chainType == HDChainType.External)
assert(ninth.address.index == 1) assert(ninth.address.index == 1)
assert(HDPath.fromString(ninthString).contains(ninth)) assert(HDPath.fromStringOpt(ninthString).contains(ninth))
val tenthString = " m / 44' / 1' / 0' / 0 / 1 " val tenthString = " m / 44' / 1' / 0' / 0 / 1 "
val tenth = LegacyHDPath.fromString(tenthString) val tenth = LegacyHDPath.fromString(tenthString)
@ -295,7 +295,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(tenth.account.index == 0) assert(tenth.account.index == 0)
assert(tenth.chain.chainType == HDChainType.External) assert(tenth.chain.chainType == HDChainType.External)
assert(tenth.address.index == 1) assert(tenth.address.index == 1)
assert(HDPath.fromString(tenthString).contains(tenth)) assert(HDPath.fromStringOpt(tenthString).contains(tenth))
val eleventhString = " m / 44' / 1' / 0' / 1 / 0 " val eleventhString = " m / 44' / 1' / 0' / 1 / 0 "
val eleventh = LegacyHDPath.fromString(eleventhString) val eleventh = LegacyHDPath.fromString(eleventhString)
@ -304,7 +304,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(eleventh.account.index == 0) assert(eleventh.account.index == 0)
assert(eleventh.chain.chainType == HDChainType.Change) assert(eleventh.chain.chainType == HDChainType.Change)
assert(eleventh.address.index == 0) assert(eleventh.address.index == 0)
assert(HDPath.fromString(eleventhString).contains(eleventh)) assert(HDPath.fromStringOpt(eleventhString).contains(eleventh))
val twelfthString = " m / 44' / 1' / 0' / 1 / 1 " val twelfthString = " m / 44' / 1' / 0' / 1 / 1 "
val twelfth = LegacyHDPath.fromString(twelfthString) val twelfth = LegacyHDPath.fromString(twelfthString)
@ -313,7 +313,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(twelfth.account.index == 0) assert(twelfth.account.index == 0)
assert(twelfth.chain.chainType == HDChainType.Change) assert(twelfth.chain.chainType == HDChainType.Change)
assert(twelfth.address.index == 1) assert(twelfth.address.index == 1)
assert(HDPath.fromString(twelfthString).contains(twelfth)) assert(HDPath.fromStringOpt(twelfthString).contains(twelfth))
val thirteenthString = " m / 44' / 1' / 1' / 0 / 0 " val thirteenthString = " m / 44' / 1' / 1' / 0 / 0 "
val thirteenth = LegacyHDPath.fromString(thirteenthString) val thirteenth = LegacyHDPath.fromString(thirteenthString)
@ -322,7 +322,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(thirteenth.account.index == 1) assert(thirteenth.account.index == 1)
assert(thirteenth.chain.chainType == HDChainType.External) assert(thirteenth.chain.chainType == HDChainType.External)
assert(thirteenth.address.index == 0) assert(thirteenth.address.index == 0)
assert(HDPath.fromString(thirteenthString).contains(thirteenth)) assert(HDPath.fromStringOpt(thirteenthString).contains(thirteenth))
val fourteenthString = " m / 44' / 1' / 1' / 0 / 1 " val fourteenthString = " m / 44' / 1' / 1' / 0 / 1 "
val fourteenth = LegacyHDPath.fromString(fourteenthString) val fourteenth = LegacyHDPath.fromString(fourteenthString)
@ -331,7 +331,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(fourteenth.account.index == 1) assert(fourteenth.account.index == 1)
assert(fourteenth.chain.chainType == HDChainType.External) assert(fourteenth.chain.chainType == HDChainType.External)
assert(fourteenth.address.index == 1) assert(fourteenth.address.index == 1)
assert(HDPath.fromString(fourteenthString).contains(fourteenth)) assert(HDPath.fromStringOpt(fourteenthString).contains(fourteenth))
val fifteenthString = " m / 44' / 1' / 1' / 1 / 0 " val fifteenthString = " m / 44' / 1' / 1' / 1 / 0 "
val fifteenth = LegacyHDPath.fromString(fifteenthString) val fifteenth = LegacyHDPath.fromString(fifteenthString)
@ -340,7 +340,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(fifteenth.account.index == 1) assert(fifteenth.account.index == 1)
assert(fifteenth.chain.chainType == HDChainType.Change) assert(fifteenth.chain.chainType == HDChainType.Change)
assert(fifteenth.address.index == 0) assert(fifteenth.address.index == 0)
assert(HDPath.fromString(fifteenthString).contains(fifteenth)) assert(HDPath.fromStringOpt(fifteenthString).contains(fifteenth))
val sixteenthString = " m / 44' / 1' / 1' / 1 / 1 " val sixteenthString = " m / 44' / 1' / 1' / 1 / 1 "
val sixteenth = LegacyHDPath.fromString(sixteenthString) val sixteenth = LegacyHDPath.fromString(sixteenthString)
@ -349,7 +349,7 @@ class HDPathTest extends BitcoinSUnitTest {
assert(sixteenth.account.index == 1) assert(sixteenth.account.index == 1)
assert(sixteenth.chain.chainType == HDChainType.Change) assert(sixteenth.chain.chainType == HDChainType.Change)
assert(sixteenth.address.index == 1) assert(sixteenth.address.index == 1)
assert(HDPath.fromString(sixteenthString).contains(sixteenth)) assert(HDPath.fromStringOpt(sixteenthString).contains(sixteenth))
} }
@ -372,10 +372,10 @@ class HDPathTest extends BitcoinSUnitTest {
val xpriv = seed.toExtPrivateKey(ExtKeyVersion.SegWitMainNetPriv) val xpriv = seed.toExtPrivateKey(ExtKeyVersion.SegWitMainNetPriv)
val xpub = xpriv.extPublicKey val xpub = xpriv.extPublicKey
assert(ExtPrivateKey.fromString("zprvAWgYBB").isFailure) assert(ExtPrivateKey.fromStringT("zprvAWgYBB").isFailure)
val Success(expectedXpriv) = ExtPrivateKey.fromString( val Success(expectedXpriv) = ExtPrivateKey.fromStringT(
"zprvAWgYBBk7JR8Gjrh4UJQ2uJdG1r3WNRRfURiABBE3RvMXYSrRJL62XuezvGdPvG6GFBZduosCc1YP5wixPox7zhZLfiUm8aunE96BBa4Kei5") "zprvAWgYBBk7JR8Gjrh4UJQ2uJdG1r3WNRRfURiABBE3RvMXYSrRJL62XuezvGdPvG6GFBZduosCc1YP5wixPox7zhZLfiUm8aunE96BBa4Kei5")
val Success(expectedXpub) = ExtPublicKey.fromString( val Success(expectedXpub) = ExtPublicKey.fromStringT(
"zpub6jftahH18ngZxLmXaKw3GSZzZsszmt9WqedkyZdezFtWRFBZqsQH5hyUmb4pCEeZGmVfQuP5bedXTB8is6fTv19U1GQRyQUKQGUTzyHACMF") "zpub6jftahH18ngZxLmXaKw3GSZzZsszmt9WqedkyZdezFtWRFBZqsQH5hyUmb4pCEeZGmVfQuP5bedXTB8is6fTv19U1GQRyQUKQGUTzyHACMF")
assert(xpriv == expectedXpriv) assert(xpriv == expectedXpriv)
@ -489,7 +489,7 @@ class HDPathTest extends BitcoinSUnitTest {
ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.LegacyMainNetPriv, seed) ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.LegacyMainNetPriv, seed)
val path = LegacyHDPath.fromString("m/44'/0'/0'/0/0") val path = LegacyHDPath.fromString("m/44'/0'/0'/0/0")
val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(xpub) = rootXpriv.deriveChildPubKey(path)
val Success(expectedXpub) = ExtPublicKey.fromString( val Success(expectedXpub) = ExtPublicKey.fromStringT(
"xpub6FR8LqriB4qyPvdtZwhHW2HQP4daR2qXsYAAsfaiF8DoFJJ5AqGCpiGM3kFC4Z9AZWnReXrzp2nzhp91myPjz96e3wrJoMvgnCyMBjKz8vJ") "xpub6FR8LqriB4qyPvdtZwhHW2HQP4daR2qXsYAAsfaiF8DoFJJ5AqGCpiGM3kFC4Z9AZWnReXrzp2nzhp91myPjz96e3wrJoMvgnCyMBjKz8vJ")
assert(xpub == expectedXpub) assert(xpub == expectedXpub)
} }
@ -500,7 +500,7 @@ class HDPathTest extends BitcoinSUnitTest {
ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.LegacyTestNet3Priv, seed) ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.LegacyTestNet3Priv, seed)
val path = LegacyHDPath.fromString("m/44'/0'/0'/0/0") val path = LegacyHDPath.fromString("m/44'/0'/0'/0/0")
val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(xpub) = rootXpriv.deriveChildPubKey(path)
val Success(expectedXpub) = ExtPublicKey.fromString( val Success(expectedXpub) = ExtPublicKey.fromStringT(
"tpubDFnks5gPtLoRfipk28gNhwcmiBjEQRLbRAkUEDdrb2ygzaxnF47Hy9wBHnKyb46QMRKLG7NsM8d3PzddAqEysaYw7YbcUtavNAZkwjM7aqi") "tpubDFnks5gPtLoRfipk28gNhwcmiBjEQRLbRAkUEDdrb2ygzaxnF47Hy9wBHnKyb46QMRKLG7NsM8d3PzddAqEysaYw7YbcUtavNAZkwjM7aqi")
assert(xpub == expectedXpub) assert(xpub == expectedXpub)
} }
@ -511,7 +511,7 @@ class HDPathTest extends BitcoinSUnitTest {
ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.NestedSegWitMainNetPriv, seed) ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.NestedSegWitMainNetPriv, seed)
val path = NestedSegWitHDPath.fromString("m/49'/0'/0'/0/0") val path = NestedSegWitHDPath.fromString("m/49'/0'/0'/0/0")
val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(xpub) = rootXpriv.deriveChildPubKey(path)
val Success(expectedXpub) = ExtPublicKey.fromString( val Success(expectedXpub) = ExtPublicKey.fromStringT(
"ypub6c6461WnUp9LoRskZCU3bHBJahDvtrPwCCo1WEtuhsrFGZ8Mn2YMNGab2tj5eujgsMx5U1BZz7hA1q87ZdVSXZdArxM9G5Y9iZchQFrov4q") "ypub6c6461WnUp9LoRskZCU3bHBJahDvtrPwCCo1WEtuhsrFGZ8Mn2YMNGab2tj5eujgsMx5U1BZz7hA1q87ZdVSXZdArxM9G5Y9iZchQFrov4q")
assert(xpub == expectedXpub) assert(xpub == expectedXpub)
} }
@ -523,7 +523,7 @@ class HDPathTest extends BitcoinSUnitTest {
seed) seed)
val path = NestedSegWitHDPath.fromString("m/49'/0'/0'/0/0") val path = NestedSegWitHDPath.fromString("m/49'/0'/0'/0/0")
val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(xpub) = rootXpriv.deriveChildPubKey(path)
val Success(expectedXpub) = ExtPublicKey.fromString( val Success(expectedXpub) = ExtPublicKey.fromStringT(
"upub5JkzsLq7t5yRQF7HDmKYkvoHtpe98NRwXki8NfKNBrLj49sSmPt6t1x2x4tjfH81EoUrU6oL9UGxUgfrgqqPLctmPbZSvSGCdfN7qyMHU7g") "upub5JkzsLq7t5yRQF7HDmKYkvoHtpe98NRwXki8NfKNBrLj49sSmPt6t1x2x4tjfH81EoUrU6oL9UGxUgfrgqqPLctmPbZSvSGCdfN7qyMHU7g")
assert(xpub == expectedXpub) assert(xpub == expectedXpub)
} }
@ -534,7 +534,7 @@ class HDPathTest extends BitcoinSUnitTest {
ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.SegWitMainNetPriv, seed) ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.SegWitMainNetPriv, seed)
val path = SegWitHDPath.fromString("m/84'/0'/0'/0/0") val path = SegWitHDPath.fromString("m/84'/0'/0'/0/0")
val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(xpub) = rootXpriv.deriveChildPubKey(path)
val Success(expectedXpub) = ExtPublicKey.fromString( val Success(expectedXpub) = ExtPublicKey.fromStringT(
"zpub6vibtacmZKTajuFATBMJPq629qFzaonkAHzWDBEgpHnuhDBozTVWxbF4zJ1Hm4tdkAMJTg9kUqizEz4JQXGkxyotn3MCxbT92mJ8XVcNN5E") "zpub6vibtacmZKTajuFATBMJPq629qFzaonkAHzWDBEgpHnuhDBozTVWxbF4zJ1Hm4tdkAMJTg9kUqizEz4JQXGkxyotn3MCxbT92mJ8XVcNN5E")
assert(xpub == expectedXpub) assert(xpub == expectedXpub)
} }
@ -545,7 +545,7 @@ class HDPathTest extends BitcoinSUnitTest {
ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.SegWitTestNet3Priv, seed) ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.SegWitTestNet3Priv, seed)
val path = SegWitHDPath.fromString("m/84'/0'/0'/0/0") val path = SegWitHDPath.fromString("m/84'/0'/0'/0/0")
val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(xpub) = rootXpriv.deriveChildPubKey(path)
val Success(expectedXpub) = ExtPublicKey.fromString( val Success(expectedXpub) = ExtPublicKey.fromStringT(
"vpub5dPYfuw6xbHfLiUh7kCoZUi1TxgCpKpkVqud5bf9JGHPUovtypqGULcWuUAwmSGx7bt5TmmWeCJnhqc3Xjchn35VJgZWcxBBws3Yy6zYa7G") "vpub5dPYfuw6xbHfLiUh7kCoZUi1TxgCpKpkVqud5bf9JGHPUovtypqGULcWuUAwmSGx7bt5TmmWeCJnhqc3Xjchn35VJgZWcxBBws3Yy6zYa7G")
assert(xpub == expectedXpub) assert(xpub == expectedXpub)
} }
@ -579,14 +579,14 @@ class HDPathTest extends BitcoinSUnitTest {
// we pass in the wrong version bytes to make the test vector // we pass in the wrong version bytes to make the test vector
// from bip49 pass // from bip49 pass
val rootXpriv = seed.toExtPrivateKey(ExtKeyVersion.LegacyTestNet3Priv) val rootXpriv = seed.toExtPrivateKey(ExtKeyVersion.LegacyTestNet3Priv)
val Success(expectedRootXpriv) = ExtPrivateKey.fromString( val Success(expectedRootXpriv) = ExtPrivateKey.fromStringT(
"tprv8ZgxMBicQKsPe5YMU9gHen4Ez3ApihUfykaqUorj9t6FDqy3nP6eoXiAo2ssvpAjoLroQxHqr3R5nE3a5dU3DHTjTgJDd7zrbniJr6nrCzd") "tprv8ZgxMBicQKsPe5YMU9gHen4Ez3ApihUfykaqUorj9t6FDqy3nP6eoXiAo2ssvpAjoLroQxHqr3R5nE3a5dU3DHTjTgJDd7zrbniJr6nrCzd")
val path = NestedSegWitHDPath.fromString("m/49'/1'/0'/0/0") val path = NestedSegWitHDPath.fromString("m/49'/1'/0'/0/0")
val firstAccount = path.account val firstAccount = path.account
val accountXpriv = rootXpriv.deriveChildPrivKey(firstAccount) val accountXpriv = rootXpriv.deriveChildPrivKey(firstAccount)
val Success(expectedAccountXpriv) = ExtPrivateKey.fromString( val Success(expectedAccountXpriv) = ExtPrivateKey.fromStringT(
"tprv8gRrNu65W2Msef2BdBSUgFdRTGzC8EwVXnV7UGS3faeXtuMVtGfEdidVeGbThs4ELEoayCAzZQ4uUji9DUiAs7erdVskqju7hrBcDvDsdbY") "tprv8gRrNu65W2Msef2BdBSUgFdRTGzC8EwVXnV7UGS3faeXtuMVtGfEdidVeGbThs4ELEoayCAzZQ4uUji9DUiAs7erdVskqju7hrBcDvDsdbY")
assert(expectedAccountXpriv == accountXpriv) assert(expectedAccountXpriv == accountXpriv)
@ -640,9 +640,9 @@ class HDPathTest extends BitcoinSUnitTest {
val accountXpriv = rootXpriv.deriveChildPrivKey(legacyPathAccount) val accountXpriv = rootXpriv.deriveChildPrivKey(legacyPathAccount)
val accountXpub = accountXpriv.extPublicKey val accountXpub = accountXpriv.extPublicKey
val Success(expectedAccountXpriv) = ExtPrivateKey.fromString( val Success(expectedAccountXpriv) = ExtPrivateKey.fromStringT(
"xprv9xpXFhFpqdQK3TmytPBqXtGSwS3DLjojFhTGht8gwAAii8py5X6pxeBnQ6ehJiyJ6nDjWGJfZ95WxByFXVkDxHXrqu53WCRGypk2ttuqncb") "xprv9xpXFhFpqdQK3TmytPBqXtGSwS3DLjojFhTGht8gwAAii8py5X6pxeBnQ6ehJiyJ6nDjWGJfZ95WxByFXVkDxHXrqu53WCRGypk2ttuqncb")
val Success(expectedAccountXpub) = ExtPublicKey.fromString( val Success(expectedAccountXpub) = ExtPublicKey.fromStringT(
"xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj") "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj")
assert(expectedAccountXpriv == accountXpriv) assert(expectedAccountXpriv == accountXpriv)
@ -659,9 +659,9 @@ class HDPathTest extends BitcoinSUnitTest {
val accountXpriv = rootXpriv.deriveChildPrivKey(nestedSegwithPathAccount) val accountXpriv = rootXpriv.deriveChildPrivKey(nestedSegwithPathAccount)
val accountXpub = accountXpriv.extPublicKey val accountXpub = accountXpriv.extPublicKey
val Success(expectedAccountXpriv) = ExtPrivateKey.fromString( val Success(expectedAccountXpriv) = ExtPrivateKey.fromStringT(
"yprvAHwhK6RbpuS3dgCYHM5jc2ZvEKd7Bi61u9FVhYMpgMSuZS613T1xxQeKTffhrHY79hZ5PsskBjcc6C2V7DrnsMsNaGDaWev3GLRQRgV7hxF") "yprvAHwhK6RbpuS3dgCYHM5jc2ZvEKd7Bi61u9FVhYMpgMSuZS613T1xxQeKTffhrHY79hZ5PsskBjcc6C2V7DrnsMsNaGDaWev3GLRQRgV7hxF")
val Success(expectedAccountXpub) = ExtPublicKey.fromString( val Success(expectedAccountXpub) = ExtPublicKey.fromStringT(
"ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP") "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP")
assert(expectedAccountXpriv == accountXpriv) assert(expectedAccountXpriv == accountXpriv)
@ -677,9 +677,9 @@ class HDPathTest extends BitcoinSUnitTest {
val accountXpriv = rootXpriv.deriveChildPrivKey(segwithPathAccount) val accountXpriv = rootXpriv.deriveChildPrivKey(segwithPathAccount)
val accountXpub = accountXpriv.extPublicKey val accountXpub = accountXpriv.extPublicKey
val Success(expectedAccountXpriv) = ExtPrivateKey.fromString( val Success(expectedAccountXpriv) = ExtPrivateKey.fromStringT(
"zprvAdG4iTXWBoARxkkzNpNh8r6Qag3irQB8PzEMkAFeTRXxHpbF9z4QgEvBRmfvqWvGp42t42nvgGpNgYSJA9iefm1yYNZKEm7z6qUWCroSQnE") "zprvAdG4iTXWBoARxkkzNpNh8r6Qag3irQB8PzEMkAFeTRXxHpbF9z4QgEvBRmfvqWvGp42t42nvgGpNgYSJA9iefm1yYNZKEm7z6qUWCroSQnE")
val Success(expectedAccountXpub) = ExtPublicKey.fromString( val Success(expectedAccountXpub) = ExtPublicKey.fromStringT(
"zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs") "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs")
assert(expectedAccountXpriv == accountXpriv) assert(expectedAccountXpriv == accountXpriv)

View file

@ -46,25 +46,25 @@ class LnHumanReadablePartTest extends BitcoinSUnitTest {
it must "deserialize hrp from string" in { it must "deserialize hrp from string" in {
LnHumanReadablePart.fromString("lnbc").get must be( LnHumanReadablePart.fromString("lnbc") must be(
LnHumanReadablePart(LnBitcoinMainNet)) LnHumanReadablePart(LnBitcoinMainNet))
LnHumanReadablePart.fromString("lntb").get must be( LnHumanReadablePart.fromString("lntb") must be(
LnHumanReadablePart(LnBitcoinTestNet)) LnHumanReadablePart(LnBitcoinTestNet))
LnHumanReadablePart.fromString("lnbcrt").get must be( LnHumanReadablePart.fromString("lnbcrt") must be(
LnHumanReadablePart(LnBitcoinRegTest)) LnHumanReadablePart(LnBitcoinRegTest))
LnHumanReadablePart.fromString("lnbc1m").get must be( LnHumanReadablePart.fromString("lnbc1m") must be(
LnHumanReadablePart(LnBitcoinMainNet, mBtcOpt)) LnHumanReadablePart(LnBitcoinMainNet, mBtcOpt))
LnHumanReadablePart.fromString("lntb1m").get must be( LnHumanReadablePart.fromString("lntb1m") must be(
LnHumanReadablePart(LnBitcoinTestNet, mBtcOpt)) LnHumanReadablePart(LnBitcoinTestNet, mBtcOpt))
LnHumanReadablePart.fromString("lnbcrt1m").get must be( LnHumanReadablePart.fromString("lnbcrt1m") must be(
LnHumanReadablePart(LnBitcoinRegTest, mBtcOpt)) LnHumanReadablePart(LnBitcoinRegTest, mBtcOpt))
} }
it must "fail to deserialize hrp from invalid string" in { it must "fail to deserialize hrp from invalid string" in {
LnHumanReadablePart.fromString("invalid").isFailure must be(true) LnHumanReadablePart.fromStringT("invalid").isFailure must be(true)
LnHumanReadablePart.fromString("lnbc9000").isFailure must be(true) LnHumanReadablePart.fromStringT("lnbc9000").isFailure must be(true)
LnHumanReadablePart.fromString("lnbc90z0m").isFailure must be(true) LnHumanReadablePart.fromStringT("lnbc90z0m").isFailure must be(true)
} }
} }

View file

@ -422,7 +422,7 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest {
it must "have serialization symmetry for LnHrps" in { it must "have serialization symmetry for LnHrps" in {
forAll(LnInvoiceGen.lnHrp) { hrp => forAll(LnInvoiceGen.lnHrp) { hrp =>
LnHumanReadablePart.fromString(hrp.toString).get == hrp LnHumanReadablePart.fromString(hrp.toString) == hrp
} }
} }

View file

@ -60,7 +60,7 @@ class PSBTSerializerTest extends BitcoinSAsyncTest {
val xpub1 = ExtPublicKey val xpub1 = ExtPublicKey
.fromString( .fromString(
"tpubDBkJeJo2X94Yq3RVz65DoUgyLUkaDrkfyrn2VcgyCRSKCRonvKvCF2FpYDGJWDkdRHBajXJGpc63GnumUt63ySvqCu2XaTRGVTKMYGuFk9H") "tpubDBkJeJo2X94Yq3RVz65DoUgyLUkaDrkfyrn2VcgyCRSKCRonvKvCF2FpYDGJWDkdRHBajXJGpc63GnumUt63ySvqCu2XaTRGVTKMYGuFk9H")
.get
val finger1 = hex"d90c6a4f" val finger1 = hex"d90c6a4f"
val path1 = BIP32Path.fromString("m/174'/0'") val path1 = BIP32Path.fromString("m/174'/0'")
@ -69,7 +69,7 @@ class PSBTSerializerTest extends BitcoinSAsyncTest {
val xpub2 = ExtPublicKey val xpub2 = ExtPublicKey
.fromString( .fromString(
"tpubDBkJeJo2X94YsvtBEU1eKoibEWiNv51nW5iHhs6VZp59jsE6nen8KZMFyGHuGbCvqjRqirgeMcfpVBkttpUUT6brm4duzSGoZeTbhqCNUu6") "tpubDBkJeJo2X94YsvtBEU1eKoibEWiNv51nW5iHhs6VZp59jsE6nen8KZMFyGHuGbCvqjRqirgeMcfpVBkttpUUT6brm4duzSGoZeTbhqCNUu6")
.get
val finger2 = hex"d90c6a4f" val finger2 = hex"d90c6a4f"
val path2 = BIP32Path.fromString("m/174'/1'") val path2 = BIP32Path.fromString("m/174'/1'")

View file

@ -73,7 +73,6 @@ class PSBTUnitTest extends BitcoinSAsyncTest {
val extKey = ExtKey val extKey = ExtKey
.fromString( .fromString(
"tprv8ZgxMBicQKsPd9TeAdPADNnSyH9SSUUbTVeFszDE23Ki6TBB5nCefAdHkK8Fm3qMQR6sHwA56zqRmKmxnHk37JkiFzvncDqoKmPWubu7hDF") "tprv8ZgxMBicQKsPd9TeAdPADNnSyH9SSUUbTVeFszDE23Ki6TBB5nCefAdHkK8Fm3qMQR6sHwA56zqRmKmxnHk37JkiFzvncDqoKmPWubu7hDF")
.get
val psbt = start val psbt = start
.addUTXOToInput( .addUTXOToInput(

View file

@ -7,7 +7,7 @@ class ScriptTypeTest extends BitcoinSUnitTest {
it must "have serialization symmetry" in { it must "have serialization symmetry" in {
ScriptType.all.foreach { scriptType => ScriptType.all.foreach { scriptType =>
val newScriptType = ScriptType.fromString(scriptType.toString) val newScriptType = ScriptType.fromStringOpt(scriptType.toString)
assert(newScriptType.contains(scriptType)) assert(newScriptType.contains(scriptType))
} }
@ -16,7 +16,7 @@ class ScriptTypeTest extends BitcoinSUnitTest {
it must "fail when nonsense ScriptType is used" in { it must "fail when nonsense ScriptType is used" in {
val lyrics = "Never gonna give you up, never gonna let you down" val lyrics = "Never gonna give you up, never gonna let you down"
assert(ScriptType.fromString(lyrics).isEmpty) assert(ScriptType.fromStringOpt(lyrics).isEmpty)
assertThrows[IllegalArgumentException](ScriptType.fromStringExn(lyrics)) assertThrows[RuntimeException](ScriptType.fromString(lyrics))
} }
} }

View file

@ -7,9 +7,9 @@ import org.bitcoins.testkit.util.BitcoinSUnitTest
*/ */
class ArithmeticOperationsFactoryTest extends BitcoinSUnitTest { class ArithmeticOperationsFactoryTest extends BitcoinSUnitTest {
"ArithmeticOperationsFactory" must "match strings with arithmetic operations" in { "ArithmeticOperationsFactory" must "match strings with arithmetic operations" in {
ArithmeticOperation.fromString("OP_1ADD") must be(Some(OP_1ADD)) ArithmeticOperation.fromStringOpt("OP_1ADD") must be(Some(OP_1ADD))
ArithmeticOperation.fromString("OP_ADD") must be(Some(OP_ADD)) ArithmeticOperation.fromStringOpt("OP_ADD") must be(Some(OP_ADD))
ArithmeticOperation.fromString("OP_LESSTHAN") must be(Some(OP_LESSTHAN)) ArithmeticOperation.fromStringOpt("OP_LESSTHAN") must be(Some(OP_LESSTHAN))
ArithmeticOperation.fromString("OP_RANDOM") must be(None) ArithmeticOperation.fromStringOpt("OP_RANDOM") must be(None)
} }
} }

View file

@ -8,8 +8,9 @@ import org.bitcoins.testkit.util.BitcoinSUnitTest
class BitwiseOperationsFactoryTest extends BitcoinSUnitTest { class BitwiseOperationsFactoryTest extends BitcoinSUnitTest {
"BitwiseOperationsFactory" must "match strings with bitwise operations" in { "BitwiseOperationsFactory" must "match strings with bitwise operations" in {
BitwiseOperation.fromString("OP_EQUAL") must be(Some(OP_EQUAL)) BitwiseOperation.fromStringOpt("OP_EQUAL") must be(Some(OP_EQUAL))
BitwiseOperation.fromString("OP_EQUALVERIFY") must be(Some(OP_EQUALVERIFY)) BitwiseOperation.fromStringOpt("OP_EQUALVERIFY") must be(
BitwiseOperation.fromString("RANDOM") must be(None) Some(OP_EQUALVERIFY))
BitwiseOperation.fromStringOpt("RANDOM") must be(None)
} }
} }

View file

@ -8,13 +8,13 @@ import org.bitcoins.testkit.util.BitcoinSUnitTest
class ControlOperationsFactoryTest extends BitcoinSUnitTest { class ControlOperationsFactoryTest extends BitcoinSUnitTest {
"ControlOperationsFactory" must "match a string with a control operation" in { "ControlOperationsFactory" must "match a string with a control operation" in {
ControlOperations.fromString("OP_ELSE") must be(Some(OP_ELSE)) ControlOperations.fromStringOpt("OP_ELSE") must be(Some(OP_ELSE))
ControlOperations.fromString("OP_ENDIF") must be(Some(OP_ENDIF)) ControlOperations.fromStringOpt("OP_ENDIF") must be(Some(OP_ENDIF))
ControlOperations.fromString("OP_IF") must be(Some(OP_IF)) ControlOperations.fromStringOpt("OP_IF") must be(Some(OP_IF))
ControlOperations.fromString("OP_NOTIF") must be(Some(OP_NOTIF)) ControlOperations.fromStringOpt("OP_NOTIF") must be(Some(OP_NOTIF))
ControlOperations.fromString("OP_RETURN") must be(Some(OP_RETURN)) ControlOperations.fromStringOpt("OP_RETURN") must be(Some(OP_RETURN))
ControlOperations.fromString("OP_VERIFY") must be(Some(OP_VERIFY)) ControlOperations.fromStringOpt("OP_VERIFY") must be(Some(OP_VERIFY))
ControlOperations.fromString("RANDOM") must be(None) ControlOperations.fromStringOpt("RANDOM") must be(None)
} }
} }

View file

@ -8,9 +8,9 @@ import org.bitcoins.testkit.util.BitcoinSUnitTest
class CryptoOperationsFactoryTest extends BitcoinSUnitTest { class CryptoOperationsFactoryTest extends BitcoinSUnitTest {
"CryptoOperationsFactory" must "match strings with crypto operations" in { "CryptoOperationsFactory" must "match strings with crypto operations" in {
CryptoOperation.fromString("OP_CHECKSIG") must be(Some(OP_CHECKSIG)) CryptoOperation.fromStringOpt("OP_CHECKSIG") must be(Some(OP_CHECKSIG))
CryptoOperation.fromString("OP_HASH160") must be(Some(OP_HASH160)) CryptoOperation.fromStringOpt("OP_HASH160") must be(Some(OP_HASH160))
CryptoOperation.fromString("OP_SHA256") must be(Some(OP_SHA256)) CryptoOperation.fromStringOpt("OP_SHA256") must be(Some(OP_SHA256))
CryptoOperation.fromString("RANDOM") must be(None) CryptoOperation.fromStringOpt("RANDOM") must be(None)
} }
} }

View file

@ -8,63 +8,60 @@ import org.bitcoins.testkit.util.BitcoinSUnitTest
class ScriptFlagFactoryTest extends BitcoinSUnitTest { class ScriptFlagFactoryTest extends BitcoinSUnitTest {
"ScriptFlagFactory" must "find a NONE script flag" in { "ScriptFlagFactory" must "find a NONE script flag" in {
ScriptFlagFactory.fromString("NONE").get must be(ScriptVerifyNone) ScriptFlagFactory.fromString("NONE") must be(ScriptVerifyNone)
} }
it must "find a P2SH script flag" in { it must "find a P2SH script flag" in {
ScriptFlagFactory.fromString("P2SH").get must be(ScriptVerifyP2SH) ScriptFlagFactory.fromString("P2SH") must be(ScriptVerifyP2SH)
} }
it must "find a STRICTENC flag" in { it must "find a STRICTENC flag" in {
ScriptFlagFactory.fromString("STRICTENC").get must be(ScriptVerifyStrictEnc) ScriptFlagFactory.fromString("STRICTENC") must be(ScriptVerifyStrictEnc)
} }
it must "find a DERSIG flag" in { it must "find a DERSIG flag" in {
ScriptFlagFactory.fromString("DERSIG").get must be(ScriptVerifyDerSig) ScriptFlagFactory.fromString("DERSIG") must be(ScriptVerifyDerSig)
} }
it must "find a LOW_S flag" in { it must "find a LOW_S flag" in {
ScriptFlagFactory.fromString("LOW_S").get must be(ScriptVerifyLowS) ScriptFlagFactory.fromString("LOW_S") must be(ScriptVerifyLowS)
} }
it must "find a SIGPUSHONLY flag" in { it must "find a SIGPUSHONLY flag" in {
ScriptFlagFactory.fromString("SIGPUSHONLY").get must be( ScriptFlagFactory.fromString("SIGPUSHONLY") must be(ScriptVerifySigPushOnly)
ScriptVerifySigPushOnly)
} }
it must "find a MINIMALDATA flag" in { it must "find a MINIMALDATA flag" in {
ScriptFlagFactory.fromString("MINIMALDATA").get must be( ScriptFlagFactory.fromString("MINIMALDATA") must be(ScriptVerifyMinimalData)
ScriptVerifyMinimalData)
} }
it must "find a NULLDUMMY flag" in { it must "find a NULLDUMMY flag" in {
ScriptFlagFactory.fromString("NULLDUMMY").get must be(ScriptVerifyNullDummy) ScriptFlagFactory.fromString("NULLDUMMY") must be(ScriptVerifyNullDummy)
} }
it must "find a DISCOURAGE_UPGRADABLE_NOPS flag" in { it must "find a DISCOURAGE_UPGRADABLE_NOPS flag" in {
ScriptFlagFactory.fromString("DISCOURAGE_UPGRADABLE_NOPS").get must be( ScriptFlagFactory.fromString("DISCOURAGE_UPGRADABLE_NOPS") must be(
ScriptVerifyDiscourageUpgradableNOPs) ScriptVerifyDiscourageUpgradableNOPs)
} }
it must "find a CLEANSTACK flag" in { it must "find a CLEANSTACK flag" in {
ScriptFlagFactory.fromString("CLEANSTACK").get must be( ScriptFlagFactory.fromString("CLEANSTACK") must be(ScriptVerifyCleanStack)
ScriptVerifyCleanStack)
} }
it must "find a CHECKLOCKTIMEVERIFY flag" in { it must "find a CHECKLOCKTIMEVERIFY flag" in {
ScriptFlagFactory.fromString("CHECKLOCKTIMEVERIFY").get must be( ScriptFlagFactory.fromString("CHECKLOCKTIMEVERIFY") must be(
ScriptVerifyCheckLocktimeVerify) ScriptVerifyCheckLocktimeVerify)
} }
it must "find a CHECKSEQUENCEVERIFY flag" in { it must "find a CHECKSEQUENCEVERIFY flag" in {
ScriptFlagFactory.fromString("CHECKSEQUENCEVERIFY").get must be( ScriptFlagFactory.fromString("CHECKSEQUENCEVERIFY") must be(
ScriptVerifyCheckSequenceVerify) ScriptVerifyCheckSequenceVerify)
} }
it must "match a string version of a script flag" in { it must "match a string version of a script flag" in {
val str = "MINIMALDATA" val str = "MINIMALDATA"
ScriptFlagFactory.fromString(str) must be(Some(ScriptVerifyMinimalData)) ScriptFlagFactory.fromStringOpt(str) must be(Some(ScriptVerifyMinimalData))
} }
it must "match a comma separated list of flags" in { it must "match a comma separated list of flags" in {

View file

@ -8,7 +8,7 @@ import org.bitcoins.testkit.util.BitcoinSUnitTest
class LocktimeOperationFactoryTest extends BitcoinSUnitTest { class LocktimeOperationFactoryTest extends BitcoinSUnitTest {
"LocktimeOperationFactory" must "match lock time operations from strings" in { "LocktimeOperationFactory" must "match lock time operations from strings" in {
LocktimeOperation.fromString("OP_CHECKLOCKTIMEVERIFY") must be( LocktimeOperation.fromStringOpt("OP_CHECKLOCKTIMEVERIFY") must be(
Some(OP_CHECKLOCKTIMEVERIFY)) Some(OP_CHECKLOCKTIMEVERIFY))
} }

View file

@ -8,9 +8,10 @@ import org.bitcoins.testkit.util.BitcoinSUnitTest
class StackOperationFactoryTest extends BitcoinSUnitTest { class StackOperationFactoryTest extends BitcoinSUnitTest {
"StackOperationFactory" must "match correct operations with their strings" in { "StackOperationFactory" must "match correct operations with their strings" in {
StackOperation.fromString("OP_DUP") must be(Some(OP_DUP)) StackOperation.fromStringOpt("OP_DUP") must be(Some(OP_DUP))
StackOperation.fromString("OP_FROMALTSTACK") must be(Some(OP_FROMALTSTACK)) StackOperation.fromStringOpt("OP_FROMALTSTACK") must be(
StackOperation.fromString("RANDOM_OP") must be(None) Some(OP_FROMALTSTACK))
StackOperation.fromString("OP_IFDUP") must be(Some(OP_IFDUP)) StackOperation.fromStringOpt("RANDOM_OP") must be(None)
StackOperation.fromStringOpt("OP_IFDUP") must be(Some(OP_IFDUP))
} }
} }

View file

@ -7,13 +7,13 @@ class AddressTagTest extends BitcoinSUnitTest {
behavior of "AddressTag" behavior of "AddressTag"
it must "read StorageLocationTag from string" in { it must "read StorageLocationTag from string" in {
StorageLocationTag.fromString("HotStorage").get must be( StorageLocationTag.fromString("HotStorage") must be(
StorageLocationTag.HotStorage) StorageLocationTag.HotStorage)
StorageLocationTag.fromString("ColdStorage").get must be( StorageLocationTag.fromString("ColdStorage") must be(
StorageLocationTag.ColdStorage) StorageLocationTag.ColdStorage)
StorageLocationTag.fromString("DeepColdStorage").get must be( StorageLocationTag.fromString("DeepColdStorage") must be(
StorageLocationTag.DeepColdStorage) StorageLocationTag.DeepColdStorage)
} }

View file

@ -7,19 +7,18 @@ class TxoStateTest extends BitcoinSUnitTest {
behavior of "TxoState" behavior of "TxoState"
it must "read from string" in { it must "read from string" in {
TxoState.fromString("doesnotexist").get must be(TxoState.DoesNotExist) TxoState.fromString("doesnotexist") must be(TxoState.DoesNotExist)
TxoState.fromString("PendingConfirmationsReceived").get must be( TxoState.fromString("PendingConfirmationsReceived") must be(
TxoState.PendingConfirmationsReceived) TxoState.PendingConfirmationsReceived)
TxoState.fromString("ConfirmedReceived").get must be( TxoState.fromString("ConfirmedReceived") must be(TxoState.ConfirmedReceived)
TxoState.ConfirmedReceived)
TxoState.fromString("Reserved").get must be(TxoState.Reserved) TxoState.fromString("Reserved") must be(TxoState.Reserved)
TxoState.fromString("PendingConfirmationsSpent").get must be( TxoState.fromString("PendingConfirmationsSpent") must be(
TxoState.PendingConfirmationsSpent) TxoState.PendingConfirmationsSpent)
TxoState.fromString("ConfirmedSpent").get must be(TxoState.ConfirmedSpent) TxoState.fromString("ConfirmedSpent") must be(TxoState.ConfirmedSpent)
} }
} }

View file

@ -1,9 +1,11 @@
package org.bitcoins.core.api.wallet package org.bitcoins.core.api.wallet
import org.bitcoins.crypto.StringFactory
/** Represents the various ways the wallet can do coin selection */ /** Represents the various ways the wallet can do coin selection */
sealed abstract class CoinSelectionAlgo sealed abstract class CoinSelectionAlgo
object CoinSelectionAlgo { object CoinSelectionAlgo extends StringFactory[CoinSelectionAlgo] {
/** Randomly selects utxos until it has enough to fund the desired amount, /** Randomly selects utxos until it has enough to fund the desired amount,
* should only be used for research purposes * should only be used for research purposes
@ -32,7 +34,13 @@ object CoinSelectionAlgo {
AccumulateSmallestViable, AccumulateSmallestViable,
StandardAccumulate) StandardAccumulate)
def fromString(str: String): Option[CoinSelectionAlgo] = { override def fromStringOpt(str: String): Option[CoinSelectionAlgo] = {
all.find(state => str.toLowerCase() == state.toString.toLowerCase) all.find(state => str.toLowerCase() == state.toString.toLowerCase)
} }
override def fromString(string: String): CoinSelectionAlgo = {
val algoOpt = fromStringOpt(string)
algoOpt.getOrElse(
sys.error(s"Could not find coin selection algorithm=${string}"))
}
} }

View file

@ -159,7 +159,7 @@ object Networks extends StringFactory[NetworkParameters] {
val p2pkhNetworkBytes: Seq[ByteVector] = BitcoinNetworks.p2pkhNetworkBytes val p2pkhNetworkBytes: Seq[ByteVector] = BitcoinNetworks.p2pkhNetworkBytes
val p2shNetworkBytes: Seq[ByteVector] = BitcoinNetworks.p2shNetworkBytes val p2shNetworkBytes: Seq[ByteVector] = BitcoinNetworks.p2shNetworkBytes
def fromString(string: String): NetworkParameters = override def fromString(string: String): NetworkParameters =
BitcoinNetworks.fromString(string) BitcoinNetworks.fromString(string)
def magicToNetwork: Map[ByteVector, NetworkParameters] = def magicToNetwork: Map[ByteVector, NetworkParameters] =

View file

@ -14,7 +14,8 @@ import org.bitcoins.crypto.{
Factory, Factory,
FieldElement, FieldElement,
MaskedToString, MaskedToString,
NetworkElement NetworkElement,
StringFactory
} }
import scodec.bits.{ByteVector, HexStringSyntax} import scodec.bits.{ByteVector, HexStringSyntax}
@ -125,13 +126,21 @@ sealed abstract class ExtKey extends NetworkElement {
} }
object ExtKey extends Factory[ExtKey] { object ExtKey extends Factory[ExtKey] with StringFactory[ExtKey] {
val hardenedIdx = UInt32(NumberUtil.pow2(31).toLong) val hardenedIdx = UInt32(NumberUtil.pow2(31).toLong)
val masterFingerprint: ByteVector = hex"00000000" val masterFingerprint: ByteVector = hex"00000000"
/** Takes in a base58 string and tries to convert it to an extended key */ /** Takes in a base58 string and tries to convert it to an extended key */
def fromString(base58: String): Try[ExtKey] = { override def fromString(base58: String): ExtKey = {
fromStringT(base58) match {
case Success(key) => key
case Failure(exn) =>
throw exn
}
}
override def fromStringT(base58: String): Try[ExtKey] = {
val decoded: Try[ByteVector] = Base58.decodeCheck(base58) val decoded: Try[ByteVector] = Base58.decodeCheck(base58)
val extKey = decoded.flatMap { bytes => val extKey = decoded.flatMap { bytes =>
require(bytes.size == 78, "Not 78 bytes") require(bytes.size == 78, "Not 78 bytes")
@ -268,7 +277,9 @@ sealed abstract class ExtPrivateKey
} }
} }
object ExtPrivateKey extends Factory[ExtPrivateKey] { object ExtPrivateKey
extends Factory[ExtPrivateKey]
with StringFactory[ExtPrivateKey] {
private case class ExtPrivateKeyImpl( private case class ExtPrivateKeyImpl(
version: ExtKeyPrivVersion, version: ExtKeyPrivVersion,
@ -297,8 +308,8 @@ object ExtPrivateKey extends Factory[ExtPrivateKey] {
} }
/** Takes in a base58 string and tries to convert it to an extended private key */ /** Takes in a base58 string and tries to convert it to an extended private key */
def fromString(base58: String): Try[ExtPrivateKey] = override def fromStringT(base58: String): Try[ExtPrivateKey] =
ExtKey.fromString(base58) match { ExtKey.fromStringT(base58) match {
case Success(priv: ExtPrivateKey) => Success(priv) case Success(priv: ExtPrivateKey) => Success(priv)
case Success(_: ExtPublicKey) => case Success(_: ExtPublicKey) =>
Failure( Failure(
@ -310,11 +321,18 @@ object ExtPrivateKey extends Factory[ExtPrivateKey] {
case Failure(exc) => Failure(exc) case Failure(exc) => Failure(exc)
} }
override def fromString(base58: String): ExtPrivateKey = {
fromStringT(base58) match {
case Success(key) => key
case Failure(exn) => throw exn
}
}
override def fromBytes(bytes: ByteVector): ExtPrivateKey = { override def fromBytes(bytes: ByteVector): ExtPrivateKey = {
require(bytes.size == 78, "ExtPrivateKey can only be 78 bytes") require(bytes.size == 78, "ExtPrivateKey can only be 78 bytes")
val base58 = val base58 =
Base58.encode(bytes ++ CryptoUtil.doubleSHA256(bytes).bytes.take(4)) Base58.encode(bytes ++ CryptoUtil.doubleSHA256(bytes).bytes.take(4))
ExtKey.fromString(base58) match { ExtKey.fromStringT(base58) match {
case Success(priv: ExtPrivateKey) => priv case Success(priv: ExtPrivateKey) => priv
case Success(_: ExtPublicKey) => case Success(_: ExtPublicKey) =>
throw new IllegalArgumentException( throw new IllegalArgumentException(
@ -418,7 +436,9 @@ sealed abstract class ExtPublicKey extends ExtKey {
} }
} }
object ExtPublicKey extends Factory[ExtPublicKey] { object ExtPublicKey
extends Factory[ExtPublicKey]
with StringFactory[ExtPublicKey] {
private case class ExtPublicKeyImpl( private case class ExtPublicKeyImpl(
version: ExtKeyPubVersion, version: ExtKeyPubVersion,
@ -440,8 +460,8 @@ object ExtPublicKey extends Factory[ExtPublicKey] {
} }
/** Takes in a base58 string and tries to convert it to an extended public key */ /** Takes in a base58 string and tries to convert it to an extended public key */
def fromString(base58: String): Try[ExtPublicKey] = override def fromStringT(base58: String): Try[ExtPublicKey] =
ExtKey.fromString(base58) match { ExtKey.fromStringT(base58) match {
case Success(pub: ExtPublicKey) => Success(pub) case Success(pub: ExtPublicKey) => Success(pub)
case Success(_: ExtPrivateKey) => case Success(_: ExtPrivateKey) =>
Failure( Failure(
@ -453,11 +473,18 @@ object ExtPublicKey extends Factory[ExtPublicKey] {
case Failure(fail) => Failure(fail) case Failure(fail) => Failure(fail)
} }
override def fromString(base58: String): ExtPublicKey = {
fromStringT(base58) match {
case Success(key) => key
case Failure(exn) => throw exn
}
}
override def fromBytes(bytes: ByteVector): ExtPublicKey = { override def fromBytes(bytes: ByteVector): ExtPublicKey = {
require(bytes.size == 78, "ExtPublicKey can only be 78 bytes") require(bytes.size == 78, "ExtPublicKey can only be 78 bytes")
val base58 = val base58 =
Base58.encode(bytes ++ CryptoUtil.doubleSHA256(bytes).bytes.take(4)) Base58.encode(bytes ++ CryptoUtil.doubleSHA256(bytes).bytes.take(4))
ExtKey.fromString(base58) match { ExtKey.fromStringT(base58) match {
case Success(_: ExtPrivateKey) => case Success(_: ExtPrivateKey) =>
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Cannot create ext privatkey in ExtPublicKey") "Cannot create ext privatkey in ExtPublicKey")

View file

@ -3,7 +3,7 @@ package org.bitcoins.core.hd
import org.bitcoins.core.crypto.ExtKey import org.bitcoins.core.crypto.ExtKey
import org.bitcoins.core.number.UInt32 import org.bitcoins.core.number.UInt32
import org.bitcoins.core.util.SeqWrapper import org.bitcoins.core.util.SeqWrapper
import org.bitcoins.crypto.Factory import org.bitcoins.crypto.{Factory, StringFactory}
import scodec.bits.ByteVector import scodec.bits.ByteVector
abstract class BIP32Path extends SeqWrapper[BIP32Node] { abstract class BIP32Path extends SeqWrapper[BIP32Node] {
@ -93,7 +93,7 @@ abstract class BIP32Path extends SeqWrapper[BIP32Node] {
} }
object BIP32Path extends Factory[BIP32Path] { object BIP32Path extends Factory[BIP32Path] with StringFactory[BIP32Path] {
private case class BIP32PathImpl(path: Vector[BIP32Node]) extends BIP32Path private case class BIP32PathImpl(path: Vector[BIP32Node]) extends BIP32Path
/** /**
@ -125,7 +125,7 @@ object BIP32Path extends Factory[BIP32Path] {
* and [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44]] * and [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44]]
* for examples of this notation. * for examples of this notation.
*/ */
def fromString(string: String): BIP32Path = { override def fromString(string: String): BIP32Path = {
val parts = string val parts = string
.split("/") .split("/")
.toVector .toVector
@ -167,7 +167,7 @@ object BIP32Path extends Factory[BIP32Path] {
BIP32Path(path) BIP32Path(path)
} }
def fromBytes(bytes: ByteVector): BIP32Path = override def fromBytes(bytes: ByteVector): BIP32Path =
fromBytes(bytes, littleEndian = false) fromBytes(bytes, littleEndian = false)
override def fromBytesLE(bytes: ByteVector): BIP32Path = override def fromBytesLE(bytes: ByteVector): BIP32Path =

View file

@ -1,6 +1,8 @@
package org.bitcoins.core.hd package org.bitcoins.core.hd
import scala.util.Try import org.bitcoins.crypto.StringFactory
import scala.util.{Failure, Success, Try}
private[bitcoins] trait HDPath extends BIP32Path { private[bitcoins] trait HDPath extends BIP32Path {
@ -54,12 +56,19 @@ private[bitcoins] trait HDPath extends BIP32Path {
override val path: Vector[BIP32Node] = address.path override val path: Vector[BIP32Node] = address.path
} }
object HDPath { object HDPath extends StringFactory[HDPath] {
/** Attempts to parse a string into a valid HD path */ /** Attempts to parse a string into a valid HD path */
def fromString(string: String): Option[HDPath] = override def fromStringT(string: String): Try[HDPath] =
Try(LegacyHDPath.fromString(string)) LegacyHDPath
.orElse(Try(SegWitHDPath.fromString(string))) .fromStringT(string)
.orElse(Try(NestedSegWitHDPath.fromString(string))) .orElse(SegWitHDPath.fromStringT(string))
.toOption .orElse(NestedSegWitHDPath.fromStringT(string))
override def fromString(string: String): HDPath = {
fromStringT(string) match {
case Success(path) => path
case Failure(exn) => throw exn
}
}
} }

View file

@ -1,8 +1,11 @@
package org.bitcoins.core.hd package org.bitcoins.core.hd
import org.bitcoins.crypto.StringFactory
import scala.util.Try import scala.util.Try
private[hd] trait HDPathFactory[PathType <: BIP32Path] { private[hd] trait HDPathFactory[PathType <: BIP32Path]
extends StringFactory[PathType] {
private lazy val pathName = getClass.getSimpleName private lazy val pathName = getClass.getSimpleName
@ -32,7 +35,7 @@ private[hd] trait HDPathFactory[PathType <: BIP32Path] {
} }
/** Parses a string representation of a HD path */ /** Parses a string representation of a HD path */
def fromString(string: String): PathType = { override def fromString(string: String): PathType = {
val bip32Path = BIP32Path.fromString(string) val bip32Path = BIP32Path.fromString(string)
val children = bip32Path.path val children = bip32Path.path

View file

@ -2,7 +2,7 @@ package org.bitcoins.core.p2p
import org.bitcoins.core.number.UInt64 import org.bitcoins.core.number.UInt64
import org.bitcoins.core.serializers.p2p.messages.RawServiceIdentifierSerializer import org.bitcoins.core.serializers.p2p.messages.RawServiceIdentifierSerializer
import org.bitcoins.crypto.{Factory, NetworkElement} import org.bitcoins.crypto.{Factory, NetworkElement, StringFactory}
import scodec.bits.ByteVector import scodec.bits.ByteVector
/** /**
@ -106,7 +106,9 @@ sealed trait UnknownService extends ServiceIdentifier {
override def toString(): String = s"UnknownService(${num.toLong})" override def toString(): String = s"UnknownService(${num.toLong})"
} }
object ServiceIdentifier extends Factory[ServiceIdentifier] { object ServiceIdentifier
extends Factory[ServiceIdentifier]
with StringFactory[ServiceIdentifier] {
/** /**
* This node is not a full node. * This node is not a full node.
@ -172,7 +174,7 @@ object ServiceIdentifier extends Factory[ServiceIdentifier] {
def fromBytes(bytes: ByteVector): ServiceIdentifier = def fromBytes(bytes: ByteVector): ServiceIdentifier =
RawServiceIdentifierSerializer.read(bytes) RawServiceIdentifierSerializer.read(bytes)
def fromString(string: String): ServiceIdentifier = override def fromString(string: String): ServiceIdentifier =
string match { string match {
case "NETWORK" => NODE_NETWORK case "NETWORK" => NODE_NETWORK
case "NETWORK_LIMITED" => NODE_NETWORK_LIMITED case "NETWORK_LIMITED" => NODE_NETWORK_LIMITED

View file

@ -9,6 +9,7 @@ import scala.util.{Failure, Success, Try}
abstract class AddressFactory[T <: Address] extends StringFactory[T] { abstract class AddressFactory[T <: Address] extends StringFactory[T] {
/** Same as fromString, but throws the exception */ /** Same as fromString, but throws the exception */
@deprecated(s"Use fromString() instead", "2020-08-24")
def fromStringExn(str: String): T = fromString(str) def fromStringExn(str: String): T = fromString(str)
def fromScriptPubKey(spk: ScriptPubKey, np: NetworkParameters): T = { def fromScriptPubKey(spk: ScriptPubKey, np: NetworkParameters): T = {

View file

@ -4,6 +4,7 @@ import org.bitcoins.core.config.NetworkParameters
import org.bitcoins.core.protocol.ln.LnParams._ import org.bitcoins.core.protocol.ln.LnParams._
import org.bitcoins.core.protocol.ln.currency.{LnCurrencyUnit, LnCurrencyUnits} import org.bitcoins.core.protocol.ln.currency.{LnCurrencyUnit, LnCurrencyUnits}
import org.bitcoins.core.util.Bech32HumanReadablePart import org.bitcoins.core.util.Bech32HumanReadablePart
import org.bitcoins.crypto.StringFactory
import scodec.bits.ByteVector import scodec.bits.ByteVector
import scala.util.matching.Regex import scala.util.matching.Regex
@ -34,7 +35,7 @@ sealed abstract class LnHumanReadablePart extends Bech32HumanReadablePart {
override lazy val toString: String = chars override lazy val toString: String = chars
} }
object LnHumanReadablePart { object LnHumanReadablePart extends StringFactory[LnHumanReadablePart] {
/** Prefix for generating a LN invoice on the Bitcoin MainNet */ /** Prefix for generating a LN invoice on the Bitcoin MainNet */
case class lnbc(override val amount: Option[LnCurrencyUnit]) case class lnbc(override val amount: Option[LnCurrencyUnit])
@ -55,7 +56,7 @@ object LnHumanReadablePart {
} }
/** Tries to construct a LN HRP with optional amount specified from the given string */ /** Tries to construct a LN HRP with optional amount specified from the given string */
def apply(bech32: String): Try[LnHumanReadablePart] = fromString(bech32) def apply(bech32: String): Try[LnHumanReadablePart] = fromStringT(bech32)
def apply(network: NetworkParameters): LnHumanReadablePart = { def apply(network: NetworkParameters): LnHumanReadablePart = {
val lnNetwork = LnParams.fromNetworkParameters(network) val lnNetwork = LnParams.fromNetworkParameters(network)
@ -108,7 +109,7 @@ object LnHumanReadablePart {
* and * and
* [[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#Specification BIP173]] * [[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#Specification BIP173]]
*/ */
def fromString(bech32: String): Try[LnHumanReadablePart] = { override def fromStringT(bech32: String): Try[LnHumanReadablePart] = {
//Select all of the letters, until we hit a number, as the network //Select all of the letters, until we hit a number, as the network
val networkPattern: Regex = "^[a-z]*".r val networkPattern: Regex = "^[a-z]*".r
val networkStringOpt = networkPattern.findFirstIn(bech32) val networkStringOpt = networkPattern.findFirstIn(bech32)
@ -136,4 +137,11 @@ object LnHumanReadablePart {
} }
} }
} }
override def fromString(string: String): LnHumanReadablePart = {
fromStringT(string) match {
case Success(hrp) => hrp
case Failure(exn) => throw exn
}
}
} }

View file

@ -203,7 +203,7 @@ object LnInvoice extends StringFactory[LnInvoice] with BitcoinSLogger {
throw new IllegalArgumentException("Data part is too short") throw new IllegalArgumentException("Data part is too short")
} else { } else {
val hrpValid = LnHumanReadablePart.fromString(hrp) val hrpValid = LnHumanReadablePart.fromStringT(hrp)
val dataValid = Bech32.checkDataValidity(data) val dataValid = Bech32.checkDataValidity(data)

View file

@ -2,6 +2,7 @@ package org.bitcoins.core.protocol.ln
import org.bitcoins.core.number.UInt5 import org.bitcoins.core.number.UInt5
import org.bitcoins.core.util.Bech32 import org.bitcoins.core.util.Bech32
import org.bitcoins.crypto.StringFactory
sealed abstract class LnTagPrefix { sealed abstract class LnTagPrefix {
val value: Char val value: Char
@ -13,7 +14,7 @@ sealed abstract class LnTagPrefix {
* This defines the necessary Lightning Network Tag Prefix's, as specified in BOLT-11 * This defines the necessary Lightning Network Tag Prefix's, as specified in BOLT-11
* Please see: https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#tagged-fields * Please see: https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#tagged-fields
*/ */
object LnTagPrefix { object LnTagPrefix extends StringFactory[LnTagPrefix] {
case class Unknown(value: Char) extends LnTagPrefix case class Unknown(value: Char) extends LnTagPrefix
@ -72,11 +73,11 @@ object LnTagPrefix {
.map(prefix => prefix.value -> prefix) .map(prefix => prefix.value -> prefix)
.toMap .toMap
def fromString(str: String): Option[LnTagPrefix] = { override def fromString(str: String): LnTagPrefix = {
if (str.length == 1) { if (str.length == 1) {
Option(fromChar(str.head)) fromChar(str.head)
} else { } else {
None sys.error(s"LnTagPrefix can only be one char in length, got=${str}")
} }
} }

View file

@ -1,11 +1,13 @@
package org.bitcoins.core.protocol.ln.channel package org.bitcoins.core.protocol.ln.channel
import org.bitcoins.crypto.StringFactory
/** /**
* Copied from [[https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelTypes.scala Eclair]] * Copied from [[https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelTypes.scala Eclair]]
*/ */
sealed trait ChannelState sealed trait ChannelState
object ChannelState { object ChannelState extends StringFactory[ChannelState] {
case object WAIT_FOR_INIT_INTERNAL extends ChannelState case object WAIT_FOR_INIT_INTERNAL extends ChannelState
case object WAIT_FOR_OPEN_CHANNEL extends ChannelState case object WAIT_FOR_OPEN_CHANNEL extends ChannelState
case object WAIT_FOR_ACCEPT_CHANNEL extends ChannelState case object WAIT_FOR_ACCEPT_CHANNEL extends ChannelState
@ -48,7 +50,14 @@ object ChannelState {
ERR_INFORMATION_LEAK ERR_INFORMATION_LEAK
).map(state => state.toString -> state).toMap ).map(state => state.toString -> state).toMap
def fromString(str: String): Option[ChannelState] = { override def fromStringOpt(str: String): Option[ChannelState] = {
all.get(str) all.get(str)
} }
override def fromString(str: String): ChannelState = {
fromStringOpt(str) match {
case Some(state) => state
case None => sys.error(s"Could not find channel state=${str}")
}
}
} }

View file

@ -672,7 +672,7 @@ case class PSBT(
} }
} }
object PSBT extends Factory[PSBT] { object PSBT extends Factory[PSBT] with StringFactory[PSBT] {
// The known version of PSBTs this library can process defined by https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#version-numbers // The known version of PSBTs this library can process defined by https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#version-numbers
final val knownVersions: Vector[UInt32] = Vector(UInt32.zero) final val knownVersions: Vector[UInt32] = Vector(UInt32.zero)
@ -682,7 +682,7 @@ object PSBT extends Factory[PSBT] {
final val empty = fromUnsignedTx(EmptyTransaction) final val empty = fromUnsignedTx(EmptyTransaction)
def fromString(str: String): PSBT = { override def fromString(str: String): PSBT = {
ByteVector.fromHex(str) match { ByteVector.fromHex(str) match {
case Some(hex) => case Some(hex) =>
PSBT(hex) PSBT(hex)

View file

@ -10,6 +10,7 @@ import org.bitcoins.core.script.reserved.ReservedOperation
import org.bitcoins.core.script.splice.SpliceOperation import org.bitcoins.core.script.splice.SpliceOperation
import org.bitcoins.core.script.stack.StackOperation import org.bitcoins.core.script.stack.StackOperation
import org.bitcoins.core.util.{BitcoinSLogger, BytesUtil} import org.bitcoins.core.util.{BitcoinSLogger, BytesUtil}
import org.bitcoins.crypto.StringFactory
import scodec.bits.ByteVector import scodec.bits.ByteVector
/** /**
@ -17,7 +18,9 @@ import scodec.bits.ByteVector
* Responsible for matching script op codes with their given * Responsible for matching script op codes with their given
* hexadecimal representation or byte representation * hexadecimal representation or byte representation
*/ */
trait ScriptOperationFactory[T <: ScriptOperation] extends BitcoinSLogger { trait ScriptOperationFactory[T <: ScriptOperation]
extends StringFactory[T]
with BitcoinSLogger {
/** All of the [[org.bitcoins.core.script.ScriptOperation ScriptOperation]]s for a particular `T`. */ /** All of the [[org.bitcoins.core.script.ScriptOperation ScriptOperation]]s for a particular `T`. */
def operations: Vector[T] def operations: Vector[T]
@ -25,7 +28,7 @@ trait ScriptOperationFactory[T <: ScriptOperation] extends BitcoinSLogger {
/** /**
* Finds a [[org.bitcoins.core.script.ScriptOperation ScriptOperation]] from a given string * Finds a [[org.bitcoins.core.script.ScriptOperation ScriptOperation]] from a given string
*/ */
def fromString(str: String): Option[T] = { override def fromStringOpt(str: String): Option[T] = {
val result: Option[T] = operations.find(_.toString == str) val result: Option[T] = operations.find(_.toString == str)
if (result.isEmpty) { if (result.isEmpty) {
//try and remove the 'OP_' prefix on the operations and see if it matches anything. //try and remove the 'OP_' prefix on the operations and see if it matches anything.
@ -34,6 +37,14 @@ trait ScriptOperationFactory[T <: ScriptOperation] extends BitcoinSLogger {
} else result } else result
} }
override def fromString(str: String): T = {
fromStringOpt(str) match {
case Some(op) => op
case None =>
sys.error(s"Could not find script operation=${str}")
}
}
/** /**
* Finds a [[org.bitcoins.core.script.ScriptOperation ScriptOperation]] from its hexadecimal representation. * Finds a [[org.bitcoins.core.script.ScriptOperation ScriptOperation]] from its hexadecimal representation.
*/ */

View file

@ -1,5 +1,7 @@
package org.bitcoins.core.script package org.bitcoins.core.script
import org.bitcoins.crypto.StringFactory
/** /**
* The different Bitcoin Script type variations * The different Bitcoin Script type variations
* *
@ -38,7 +40,7 @@ sealed abstract class ScriptType {
* and [[https://github.com/bitcoin/bitcoin/blob/03732f8644a449af34f4df1bb3b8915fb15ef22c/src/script/standard.cpp#L27 standarc.cpp]] * and [[https://github.com/bitcoin/bitcoin/blob/03732f8644a449af34f4df1bb3b8915fb15ef22c/src/script/standard.cpp#L27 standarc.cpp]]
* from Bitcoin Core * from Bitcoin Core
*/ */
object ScriptType { object ScriptType extends StringFactory[ScriptType] {
private[script] val all: Seq[ScriptType] = Vector( private[script] val all: Seq[ScriptType] = Vector(
NONSTANDARD, NONSTANDARD,
@ -59,15 +61,15 @@ object ScriptType {
WITNESS_COMMITMENT WITNESS_COMMITMENT
) )
def fromString(string: String): Option[ScriptType] = override def fromStringOpt(string: String): Option[ScriptType] =
all.find(_.toString == string) all.find(_.toString == string)
/** Throws if given string is invalid */ /** Throws if given string is invalid */
def fromStringExn(string: String): ScriptType = override def fromString(string: String): ScriptType =
fromString(string) fromStringOpt(string) match {
.getOrElse( case Some(scriptType) => scriptType
throw new IllegalArgumentException( case None => sys.error(s"Could not find scriptType=${string}")
s"$string is not a valid script type!")) }
final case object NONSTANDARD extends ScriptType final case object NONSTANDARD extends ScriptType

View file

@ -1,11 +1,13 @@
package org.bitcoins.core.script.flag package org.bitcoins.core.script.flag
import org.bitcoins.crypto.StringFactory
/** /**
* Created by chris on 3/23/16. * Created by chris on 3/23/16.
* Trait used to create a script flag used to evaluate scripts in a * Trait used to create a script flag used to evaluate scripts in a
* certain way * certain way
*/ */
trait ScriptFlagFactory { trait ScriptFlagFactory extends StringFactory[ScriptFlag] {
/** /**
* All the [[ScriptFlag]]s found inside of bitcoin core * All the [[ScriptFlag]]s found inside of bitcoin core
@ -33,16 +35,23 @@ trait ScriptFlagFactory {
) )
/** Takes in a string and tries to match it with a [[ScriptFlag]]. */ /** Takes in a string and tries to match it with a [[ScriptFlag]]. */
def fromString(str: String): Option[ScriptFlag] = { override def fromStringOpt(str: String): Option[ScriptFlag] = {
flags.find(_.name == str) flags.find(_.name == str)
} }
override def fromString(str: String): ScriptFlag = {
fromStringOpt(str) match {
case Some(flag) => flag
case None => sys.error(s"Could not find ScriptFlag for string=${str}")
}
}
/** /**
* Parses the given list into[[ScriptFlag]]s * Parses the given list into[[ScriptFlag]]s
* the strings that do not match a [[ScriptFlag]] are discarded. * the strings that do not match a [[ScriptFlag]] are discarded.
*/ */
def fromList(list: Seq[String]): Seq[ScriptFlag] = { def fromList(list: Seq[String]): Seq[ScriptFlag] = {
list.flatMap(fromString(_)) list.flatMap(fromStringOpt(_))
} }
/** Parses a list of [[ScriptFlag]]s that is separated by commas. */ /** Parses a list of [[ScriptFlag]]s that is separated by commas. */

View file

@ -4,7 +4,7 @@ import org.bitcoins.core.number.UInt32
import org.bitcoins.core.script._ import org.bitcoins.core.script._
import org.bitcoins.core.script.constant._ import org.bitcoins.core.script.constant._
import org.bitcoins.core.util.BytesUtil import org.bitcoins.core.util.BytesUtil
import org.bitcoins.crypto.Factory import org.bitcoins.crypto.{Factory, StringFactory}
import scodec.bits.ByteVector import scodec.bits.ByteVector
import scala.annotation.tailrec import scala.annotation.tailrec
@ -13,10 +13,12 @@ import scala.util.Try
/** /**
* Created by chris on 1/7/16. * Created by chris on 1/7/16.
*/ */
sealed abstract class ScriptParser extends Factory[Vector[ScriptToken]] { sealed abstract class ScriptParser
extends Factory[Vector[ScriptToken]]
with StringFactory[Vector[ScriptToken]] {
/** Parses a list of bytes into a list of script tokens */ /** Parses a list of bytes into a list of script tokens */
def fromBytes(bytes: ByteVector): Vector[ScriptToken] = { override def fromBytes(bytes: ByteVector): Vector[ScriptToken] = {
val scriptTokens: Vector[ScriptToken] = parse(bytes) val scriptTokens: Vector[ScriptToken] = parse(bytes)
scriptTokens scriptTokens
} }
@ -26,7 +28,7 @@ sealed abstract class ScriptParser extends Factory[Vector[ScriptToken]] {
* example: "OP_DUP OP_HASH160 e2e7c1ab3f807151e832dd1accb3d4f5d7d19b4b OP_EQUALVERIFY OP_CHECKSIG" * example: "OP_DUP OP_HASH160 e2e7c1ab3f807151e832dd1accb3d4f5d7d19b4b OP_EQUALVERIFY OP_CHECKSIG"
* example: ["0", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved (ok if not executed)"] (from script_valid.json) * example: ["0", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved (ok if not executed)"] (from script_valid.json)
*/ */
def fromString(str: String): Vector[ScriptToken] = { override def fromString(str: String): Vector[ScriptToken] = {
if ( if (
str.size > 1 && str.substring(0, 2) == "0x" && str str.size > 1 && str.substring(0, 2) == "0x" && str
.split(" ") .split(" ")
@ -97,8 +99,8 @@ sealed abstract class ScriptParser extends Factory[Vector[ScriptToken]] {
case h +: t if h == "" => loop(t, accum) case h +: t if h == "" => loop(t, accum)
case h +: t if h == "0" => loop(t, OP_0.bytes ++ accum) case h +: t if h == "0" => loop(t, OP_0.bytes ++ accum)
case h +: t if ScriptOperation.fromString(h).isDefined => case h +: t if ScriptOperation.fromStringOpt(h).isDefined =>
val op = ScriptOperation.fromString(h).get val op = ScriptOperation.fromString(h)
loop(t, op.bytes ++ accum) loop(t, op.bytes ++ accum)
case h +: t if tryParsingLong(h) => case h +: t if tryParsingLong(h) =>
val hexLong = val hexLong =

View file

@ -1,5 +1,7 @@
package org.bitcoins.core.wallet.utxo package org.bitcoins.core.wallet.utxo
import org.bitcoins.crypto.StringFactory
/** A type of address tag, many AddressTags of the same type /** A type of address tag, many AddressTags of the same type
* should inherit the AddressTagType that they all share * should inherit the AddressTagType that they all share
*/ */
@ -30,7 +32,7 @@ trait AddressTag {
def !=(at: AddressTag): Boolean = !(this == at) def !=(at: AddressTag): Boolean = !(this == at)
} }
trait AddressTagFactory[Tag <: AddressTag] { trait AddressTagFactory[Tag <: AddressTag] extends StringFactory[Tag] {
def tagType: AddressTagType def tagType: AddressTagType
@ -38,6 +40,13 @@ trait AddressTagFactory[Tag <: AddressTag] {
def all: Vector[Tag] def all: Vector[Tag]
def fromString(str: String): Option[Tag] = override def fromStringOpt(str: String): Option[Tag] =
all.find(tag => str.toLowerCase() == tag.toString.toLowerCase) all.find(tag => str.toLowerCase() == tag.toString.toLowerCase)
override def fromString(string: String): Tag = {
fromStringOpt(string) match {
case Some(t) => t
case None => sys.error(s"Could not find tag for string=${string}")
}
}
} }

View file

@ -1,5 +1,7 @@
package org.bitcoins.core.wallet.utxo package org.bitcoins.core.wallet.utxo
import org.bitcoins.crypto.StringFactory
/** /**
* An AddressTagNames that is native to Bitcoin-S. * An AddressTagNames that is native to Bitcoin-S.
* InternalAddressTagNames are still usable when using Bitcoin-S * InternalAddressTagNames are still usable when using Bitcoin-S
@ -51,26 +53,26 @@ object UnknownAddressTag {
UnknownAddressTag(tagName, UnknownAddressTagType(tagType)) UnknownAddressTag(tagName, UnknownAddressTagType(tagType))
} }
object InternalAddressTagName { object InternalAddressTagName extends StringFactory[InternalAddressTagName] {
val all: Seq[InternalAddressTagName] = StorageLocationTag.tagNames val all: Seq[InternalAddressTagName] = StorageLocationTag.tagNames
def fromStringOpt(string: String): Option[InternalAddressTagName] = override def fromStringOpt(string: String): Option[InternalAddressTagName] =
all.find(_.name.toLowerCase == string.toLowerCase) all.find(_.name.toLowerCase == string.toLowerCase)
def fromString(string: String): InternalAddressTagName = override def fromString(string: String): InternalAddressTagName =
fromStringOpt(string).getOrElse(UnknownAddressTagName(string)) fromStringOpt(string).getOrElse(UnknownAddressTagName(string))
} }
object InternalAddressTagType { object InternalAddressTagType extends StringFactory[InternalAddressTagType] {
val all: Seq[InternalAddressTagType] = val all: Seq[InternalAddressTagType] =
Vector(StorageLocationTagType, AddressLabelTagType) Vector(StorageLocationTagType, AddressLabelTagType)
def fromStringOpt(string: String): Option[InternalAddressTagType] = override def fromStringOpt(string: String): Option[InternalAddressTagType] =
all.find(_.typeName.toLowerCase == string.toLowerCase) all.find(_.typeName.toLowerCase == string.toLowerCase)
def fromString(string: String): InternalAddressTagType = override def fromString(string: String): InternalAddressTagType =
fromStringOpt(string).getOrElse(UnknownAddressTagType(string)) fromStringOpt(string).getOrElse(UnknownAddressTagType(string))
} }

View file

@ -1,5 +1,7 @@
package org.bitcoins.core.wallet.utxo package org.bitcoins.core.wallet.utxo
import org.bitcoins.crypto.StringFactory
/** Represents the various states a transaction output can be in */ /** Represents the various states a transaction output can be in */
sealed abstract class TxoState sealed abstract class TxoState
@ -7,7 +9,7 @@ sealed abstract class ReceivedState extends TxoState
sealed abstract class SpentState extends TxoState sealed abstract class SpentState extends TxoState
object TxoState { object TxoState extends StringFactory[TxoState] {
/** Means that no funds have been sent to this utxo EVER */ /** Means that no funds have been sent to this utxo EVER */
final case object DoesNotExist extends TxoState final case object DoesNotExist extends TxoState
@ -47,7 +49,15 @@ object TxoState {
PendingConfirmationsSpent, PendingConfirmationsSpent,
ConfirmedSpent) ConfirmedSpent)
def fromString(str: String): Option[TxoState] = { override def fromStringOpt(str: String): Option[TxoState] = {
all.find(state => str.toLowerCase() == state.toString.toLowerCase) all.find(state => str.toLowerCase() == state.toString.toLowerCase)
} }
override def fromString(string: String): TxoState = {
fromStringOpt(string) match {
case Some(state) => state
case None =>
sys.error(s"Could not find txo state for string=${string}")
}
}
} }

View file

@ -375,7 +375,7 @@ class AesCryptTest extends BitcoinSUnitTest {
} }
it must "fail to create an empty AES password" in { it must "fail to create an empty AES password" in {
assert(AesPassword.fromString("").isEmpty) assert(AesPassword.fromStringOpt("").isEmpty)
intercept[IllegalArgumentException] { intercept[IllegalArgumentException] {
AesPassword.fromNonEmptyString("") AesPassword.fromNonEmptyString("")
} }

View file

@ -131,7 +131,7 @@ final case class AesPassword private (private val value: String)
} }
} }
object AesPassword { object AesPassword extends StringFactory[AesPassword] {
private val KEY_SIZE = 256 private val KEY_SIZE = 256
private val ITERATIONS = 65536 private val ITERATIONS = 65536
@ -142,15 +142,24 @@ object AesPassword {
/** Tries to construct a password from the given string. Fails /** Tries to construct a password from the given string. Fails
* if the string is empty. * if the string is empty.
*/ */
def fromString(string: String): Option[AesPassword] = { override def fromStringOpt(string: String): Option[AesPassword] = {
if (string.isEmpty) None else Some(AesPassword(string)) if (string.isEmpty) None else Some(AesPassword(string))
} }
override def fromString(string: String): AesPassword = {
fromStringOpt(string) match {
case Some(password) => password
case None =>
sys.error(
s"Could not construct AesPassword from given string, not logging in case it's sensitive")
}
}
/** Constructs a password from the given string. Throws /** Constructs a password from the given string. Throws
* if the string is empty. * if the string is empty.
*/ */
def fromNonEmptyString(string: String): AesPassword = def fromNonEmptyString(string: String): AesPassword =
fromString(string).getOrElse( fromStringOpt(string).getOrElse(
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Cannot construct empty AES passwords!")) "Cannot construct empty AES passwords!"))
} }

View file

@ -164,7 +164,7 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) {
implicit val xpubMapper: BaseColumnType[ExtPublicKey] = { implicit val xpubMapper: BaseColumnType[ExtPublicKey] = {
MappedColumnType MappedColumnType
.base[ExtPublicKey, String](_.toString, ExtPublicKey.fromString(_).get) .base[ExtPublicKey, String](_.toString, ExtPublicKey.fromString(_))
} }
implicit val hdCoinTypeMapper: BaseColumnType[HDCoinType] = { implicit val hdCoinTypeMapper: BaseColumnType[HDCoinType] = {
@ -173,15 +173,11 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) {
implicit val hdPathMappper: BaseColumnType[HDPath] = implicit val hdPathMappper: BaseColumnType[HDPath] =
MappedColumnType MappedColumnType
.base[HDPath, String](_.toString, .base[HDPath, String](_.toString, HDPath.fromString(_))
HDPath.fromString(_).get
) // hm rethink .get?
implicit val segwitPathMappper: BaseColumnType[SegWitHDPath] = implicit val segwitPathMappper: BaseColumnType[SegWitHDPath] =
MappedColumnType MappedColumnType
.base[SegWitHDPath, String](_.toString, .base[SegWitHDPath, String](_.toString, SegWitHDPath.fromString)
SegWitHDPath.fromString
) // hm rethink .get?
implicit val hdChainTypeMapper: BaseColumnType[HDChainType] = implicit val hdChainTypeMapper: BaseColumnType[HDChainType] =
MappedColumnType.base[HDChainType, Int](_.index, HDChainType.fromInt) MappedColumnType.base[HDChainType, Int](_.index, HDChainType.fromInt)
@ -194,15 +190,15 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) {
implicit val bitcoinAddressMapper: BaseColumnType[BitcoinAddress] = implicit val bitcoinAddressMapper: BaseColumnType[BitcoinAddress] =
MappedColumnType MappedColumnType
.base[BitcoinAddress, String](_.value, BitcoinAddress.fromStringExn) .base[BitcoinAddress, String](_.value, BitcoinAddress.fromString)
implicit val bech32AddressMapper: BaseColumnType[Bech32Address] = implicit val bech32AddressMapper: BaseColumnType[Bech32Address] =
MappedColumnType MappedColumnType
.base[Bech32Address, String](_.value, Bech32Address.fromStringExn) .base[Bech32Address, String](_.value, Bech32Address.fromString)
implicit val scriptTypeMapper: BaseColumnType[ScriptType] = implicit val scriptTypeMapper: BaseColumnType[ScriptType] =
MappedColumnType MappedColumnType
.base[ScriptType, String](_.toString, ScriptType.fromStringExn) .base[ScriptType, String](_.toString, ScriptType.fromString)
implicit val txMapper: BaseColumnType[Transaction] = implicit val txMapper: BaseColumnType[Transaction] =
MappedColumnType.base[Transaction, String](_.hex, Transaction.fromHex) MappedColumnType.base[Transaction, String](_.hex, Transaction.fromHex)
@ -217,7 +213,7 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) {
implicit val txoStateMapper: BaseColumnType[TxoState] = { implicit val txoStateMapper: BaseColumnType[TxoState] = {
MappedColumnType MappedColumnType
.base[TxoState, String](_.toString, TxoState.fromString(_).get) .base[TxoState, String](_.toString, TxoState.fromString(_))
} }
implicit val satoshisPerByteMapper: BaseColumnType[SatoshisPerByte] = { implicit val satoshisPerByteMapper: BaseColumnType[SatoshisPerByte] = {

View file

@ -127,7 +127,7 @@ object UserIdTags extends AddressTagFactory[UserIdTag] {
override val tagNames = Vector(CompanyTagName, InsuranceFundTagName) override val tagNames = Vector(CompanyTagName, InsuranceFundTagName)
override def fromString(str: String): Option[UserIdTag] = { override def fromStringOpt(str: String): Option[UserIdTag] = {
all.find(tag => str.toLowerCase() == tag.toString.toLowerCase) match { all.find(tag => str.toLowerCase() == tag.toString.toLowerCase) match {
case Some(tag) => case Some(tag) =>
Some(tag) Some(tag)
@ -136,6 +136,14 @@ object UserIdTags extends AddressTagFactory[UserIdTag] {
} }
} }
override def fromString(str: String): UserIdTag = {
fromStringOpt(str) match {
case Some(tag) => tag
case None => sys.error(s"Could not find tag=$str")
}
}
def fromUID(uid: Long): UserIdTag = { def fromUID(uid: Long): UserIdTag = {
UserId(uid.toString) UserId(uid.toString)
} }

View file

@ -10,7 +10,7 @@ class NodeUriTest extends BitcoinSAsyncTest {
it must "read the suredbits node uri" in { it must "read the suredbits node uri" in {
val sb = val sb =
"0338f57e4e20abf4d5c86b71b59e995ce4378e373b021a7b6f41dabb42d3aad069@ln.test.suredbits.com:9735" "0338f57e4e20abf4d5c86b71b59e995ce4378e373b021a7b6f41dabb42d3aad069@ln.test.suredbits.com:9735"
val uriT = NodeUri.fromString(sb) val uriT = NodeUri.fromStringT(sb)
assert(uriT.isSuccess == true) assert(uriT.isSuccess == true)
assert(uriT.get.toString == sb) assert(uriT.get.toString == sb)
@ -29,7 +29,7 @@ class NodeUriTest extends BitcoinSAsyncTest {
val sb = val sb =
"0338f57e4e20abf4d5c86b71b59e995ce4378e373b021a7b6f41dabb42d3aad069@127.0.0.1:9735" "0338f57e4e20abf4d5c86b71b59e995ce4378e373b021a7b6f41dabb42d3aad069@127.0.0.1:9735"
val uriT = NodeUri.fromString(sb) val uriT = NodeUri.fromStringT(sb)
assert(uriT.isSuccess) assert(uriT.isSuccess)
@ -38,14 +38,14 @@ class NodeUriTest extends BitcoinSAsyncTest {
it must "fail to read a node uri without a nodeId" in { it must "fail to read a node uri without a nodeId" in {
val sb = "@ln.test.suredbits.com" val sb = "@ln.test.suredbits.com"
val uriT = NodeUri.fromString(sb) val uriT = NodeUri.fromStringT(sb)
assert(uriT.isFailure == true) assert(uriT.isFailure == true)
} }
it must "fail to read a node uri with a invalid port" in { it must "fail to read a node uri with a invalid port" in {
val sb = val sb =
"0338f57e4e20abf4d5c86b71b59e995ce4378e373b021a7b6f41dabb42d3aad069@ln.test.suredbits.com:abc2" "0338f57e4e20abf4d5c86b71b59e995ce4378e373b021a7b6f41dabb42d3aad069@ln.test.suredbits.com:abc2"
val uriT = NodeUri.fromString(sb) val uriT = NodeUri.fromStringT(sb)
assert(uriT.isFailure == true) assert(uriT.isFailure == true)
} }
} }

View file

@ -1,6 +1,7 @@
package org.bitcoins.eclair.rpc.network package org.bitcoins.eclair.rpc.network
import org.bitcoins.core.protocol.ln.node.NodeId import org.bitcoins.core.protocol.ln.node.NodeId
import org.bitcoins.crypto.StringFactory
import scala.util.{Failure, Success, Try} import scala.util.{Failure, Success, Try}
@ -8,11 +9,11 @@ case class NodeUri(nodeId: NodeId, host: String, port: Int) {
override def toString = s"$nodeId@$host:$port" override def toString = s"$nodeId@$host:$port"
} }
object NodeUri { object NodeUri extends StringFactory[NodeUri] {
private val defaultPort = ":9735" private val defaultPort = ":9735"
def fromString(uri: String): Try[NodeUri] = { override def fromStringT(uri: String): Try[NodeUri] = {
val patternWithPort = """(\w+)@([\w.]+(\w+)):(\d{2,5})""".r val patternWithPort = """(\w+)@([\w.]+(\w+)):(\d{2,5})""".r
val isUriWithPort = patternWithPort.findFirstIn(uri) val isUriWithPort = patternWithPort.findFirstIn(uri)
@ -27,8 +28,15 @@ object NodeUri {
nodeUriT nodeUriT
} }
override def fromString(string: String): NodeUri = {
fromStringT(string) match {
case Success(uri) => uri
case Failure(exn) => throw exn
}
}
def fromStringNoPort(uri: String): Try[NodeUri] = { def fromStringNoPort(uri: String): Try[NodeUri] = {
fromString(uri + defaultPort) fromStringT(uri + defaultPort)
} }
/** /**

View file

@ -29,7 +29,7 @@ class BIP39LockedKeyManagerApiTest extends KeyManagerApiUnitTest {
it must "fail to read bad json in the seed file" in { it must "fail to read bad json in the seed file" in {
val km = withInitializedKeyManager() val km = withInitializedKeyManager()
val badPassword = AesPassword.fromString("other bad password").get val badPassword = AesPassword.fromString("other bad password")
val unlockedE = BIP39LockedKeyManager.unlock(passphrase = badPassword, val unlockedE = BIP39LockedKeyManager.unlock(passphrase = badPassword,
bip39PasswordOpt = None, bip39PasswordOpt = None,
kmParams = km.kmParams) kmParams = km.kmParams)
@ -47,7 +47,7 @@ class BIP39LockedKeyManagerApiTest extends KeyManagerApiUnitTest {
val km = withInitializedKeyManager() val km = withInitializedKeyManager()
val badPath = km.kmParams.copy(seedPath = badSeedPath) val badPath = km.kmParams.copy(seedPath = badSeedPath)
val badPassword = AesPassword.fromString("other bad password").get val badPassword = AesPassword.fromString("other bad password")
val unlockedE = BIP39LockedKeyManager.unlock(badPassword, None, badPath) val unlockedE = BIP39LockedKeyManager.unlock(badPassword, None, badPath)
unlockedE match { unlockedE match {

View file

@ -87,7 +87,7 @@ case class BIP39KeyManager(
object BIP39KeyManager object BIP39KeyManager
extends BIP39KeyManagerCreateApi[BIP39KeyManager] extends BIP39KeyManagerCreateApi[BIP39KeyManager]
with BitcoinSLogger { with BitcoinSLogger {
val badPassphrase = AesPassword.fromString("changeMe").get val badPassphrase = AesPassword.fromString("changeMe")
/** Initializes the mnemonic seed and saves it to file */ /** Initializes the mnemonic seed and saves it to file */
override def initializeWithEntropy( override def initializeWithEntropy(

View file

@ -62,7 +62,7 @@ class TrezorAddressTest extends BitcoinSWalletTest with EmptyFixture {
override def reads(json: JsValue): JsResult[HDPath] = override def reads(json: JsValue): JsResult[HDPath] =
json json
.validate[String] .validate[String]
.flatMap(HDPath.fromString(_) match { .flatMap(HDPath.fromStringOpt(_) match {
case None => JsError(s"Could not read $json") case None => JsError(s"Could not read $json")
case Some(value) => JsSuccess(value) case Some(value) => JsSuccess(value)
}) })