mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-19 01:40:55 +01:00
Update scalafmt-core to 3.8.1 (#5501)
* Update scalafmt-core to 3.8.1 * Update .scalafmt.conf settings to be factory default settings * Fix typo * scalafmt * Empty commit to re-run CI * Revert some scalafmt back to original scalafmt.conf --------- Co-authored-by: Chris Stewart <stewart.chris1234@gmail.com>
This commit is contained in:
parent
9442dba217
commit
afddf73c48
@ -1,14 +1,6 @@
|
|||||||
version = "2.7.5"
|
version = "3.8.1"
|
||||||
# See Documentation at https://scalameta.org/scalafmt/#Configuration
|
# See Documentation at https://scalameta.org/scalafmt/#Configuration
|
||||||
trailingCommas = never
|
runner.dialect=scala213
|
||||||
maxColumn = 80
|
|
||||||
lineEndings = preserve
|
|
||||||
docstrings = ScalaDoc
|
|
||||||
continuationIndent {
|
|
||||||
callSite = 2
|
|
||||||
defnSite = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
align = some
|
align = some
|
||||||
align {
|
align {
|
||||||
openParenDefnSite = false
|
openParenDefnSite = false
|
||||||
@ -16,32 +8,6 @@ align {
|
|||||||
}
|
}
|
||||||
|
|
||||||
danglingParentheses {
|
danglingParentheses {
|
||||||
callSite = false
|
callSite = false
|
||||||
defnSite = false
|
defnSite = false
|
||||||
}
|
}
|
||||||
|
|
||||||
newlines {
|
|
||||||
alwaysBeforeTopLevelStatements = true
|
|
||||||
sometimesBeforeColonInMethodReturnType = false
|
|
||||||
alwaysBeforeCurlyBraceLambdaParams = false
|
|
||||||
}
|
|
||||||
|
|
||||||
assumeStandardLibraryStripMargin = true
|
|
||||||
|
|
||||||
rewrite.rules = [
|
|
||||||
SortModifiers,
|
|
||||||
RedundantParens,
|
|
||||||
SortImports
|
|
||||||
]
|
|
||||||
|
|
||||||
binPack.literalArgumentLists = true
|
|
||||||
|
|
||||||
project {
|
|
||||||
excludeFilters = [
|
|
||||||
.bloop,
|
|
||||||
.metals,
|
|
||||||
target
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Consider Rewrite Rules
|
|
||||||
|
@ -49,163 +49,186 @@ class DLCStatusTest extends BitcoinSJvmTest {
|
|||||||
|
|
||||||
assert(status.state == DLCState.Offered)
|
assert(status.state == DLCState.Offered)
|
||||||
assert(read[DLCStatus](write(status)) == status)
|
assert(read[DLCStatus](write(status)) == status)
|
||||||
assert(read[DLCStatus](
|
assert(
|
||||||
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status)
|
read[DLCStatus](
|
||||||
|
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)
|
||||||
|
) == status
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
it must "have json symmetry in DLCStatus.Accepted" in {
|
it must "have json symmetry in DLCStatus.Accepted" in {
|
||||||
forAllParallel(NumberGenerator.bool,
|
forAllParallel(
|
||||||
TLVGen.dlcOfferTLV,
|
NumberGenerator.bool,
|
||||||
NumberGenerator.bytevector) {
|
TLVGen.dlcOfferTLV,
|
||||||
case (isInit, offerTLV, contractId) =>
|
NumberGenerator.bytevector
|
||||||
val offer = DLCOffer.fromTLV(offerTLV)
|
) { case (isInit, offerTLV, contractId) =>
|
||||||
|
val offer = DLCOffer.fromTLV(offerTLV)
|
||||||
|
|
||||||
val totalCollateral = offer.contractInfo.totalCollateral
|
val totalCollateral = offer.contractInfo.totalCollateral
|
||||||
|
|
||||||
// random testnet address
|
// random testnet address
|
||||||
val payoutAddress =
|
val payoutAddress =
|
||||||
Some(
|
Some(
|
||||||
PayoutAddress(BitcoinAddress.fromString(
|
PayoutAddress(
|
||||||
"tb1q4ps6c9ewa7uca5v39fakykq9q6hpgjkxje8gve"),
|
BitcoinAddress.fromString(
|
||||||
true))
|
"tb1q4ps6c9ewa7uca5v39fakykq9q6hpgjkxje8gve"
|
||||||
|
),
|
||||||
val contact = Option.empty[String]
|
true
|
||||||
|
|
||||||
val status =
|
|
||||||
DLCStatus.Accepted(
|
|
||||||
Sha256Digest.empty,
|
|
||||||
isInit,
|
|
||||||
TimeUtil.now,
|
|
||||||
offer.tempContractId,
|
|
||||||
contractId,
|
|
||||||
offer.contractInfo,
|
|
||||||
offer.timeouts,
|
|
||||||
offer.feeRate,
|
|
||||||
totalCollateral,
|
|
||||||
offer.collateral,
|
|
||||||
payoutAddress,
|
|
||||||
contact
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
assert(status.state == DLCState.Accepted)
|
val contact = Option.empty[String]
|
||||||
assert(read[DLCStatus](write(status)) == status)
|
|
||||||
assert(read[DLCStatus](
|
val status =
|
||||||
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status)
|
DLCStatus.Accepted(
|
||||||
|
Sha256Digest.empty,
|
||||||
|
isInit,
|
||||||
|
TimeUtil.now,
|
||||||
|
offer.tempContractId,
|
||||||
|
contractId,
|
||||||
|
offer.contractInfo,
|
||||||
|
offer.timeouts,
|
||||||
|
offer.feeRate,
|
||||||
|
totalCollateral,
|
||||||
|
offer.collateral,
|
||||||
|
payoutAddress,
|
||||||
|
contact
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(status.state == DLCState.Accepted)
|
||||||
|
assert(read[DLCStatus](write(status)) == status)
|
||||||
|
assert(
|
||||||
|
read[DLCStatus](
|
||||||
|
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)
|
||||||
|
) == status
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
it must "have json symmetry in DLCStatus.Signed" in {
|
it must "have json symmetry in DLCStatus.Signed" in {
|
||||||
forAllParallel(NumberGenerator.bool,
|
forAllParallel(
|
||||||
TLVGen.dlcOfferTLV,
|
NumberGenerator.bool,
|
||||||
NumberGenerator.bytevector,
|
TLVGen.dlcOfferTLV,
|
||||||
CryptoGenerators.doubleSha256DigestBE) {
|
NumberGenerator.bytevector,
|
||||||
case (isInit, offerTLV, contractId, txId) =>
|
CryptoGenerators.doubleSha256DigestBE
|
||||||
val offer = DLCOffer.fromTLV(offerTLV)
|
) { case (isInit, offerTLV, contractId, txId) =>
|
||||||
|
val offer = DLCOffer.fromTLV(offerTLV)
|
||||||
|
|
||||||
val totalCollateral = offer.contractInfo.totalCollateral
|
val totalCollateral = offer.contractInfo.totalCollateral
|
||||||
|
|
||||||
val payoutAddress = Option.empty[PayoutAddress]
|
val payoutAddress = Option.empty[PayoutAddress]
|
||||||
|
|
||||||
val contact = Option.empty[String]
|
val contact = Option.empty[String]
|
||||||
|
|
||||||
val status =
|
val status =
|
||||||
DLCStatus.Signed(
|
DLCStatus.Signed(
|
||||||
Sha256Digest.empty,
|
Sha256Digest.empty,
|
||||||
isInit,
|
isInit,
|
||||||
TimeUtil.now,
|
TimeUtil.now,
|
||||||
offer.tempContractId,
|
offer.tempContractId,
|
||||||
contractId,
|
contractId,
|
||||||
offer.contractInfo,
|
offer.contractInfo,
|
||||||
offer.timeouts,
|
offer.timeouts,
|
||||||
offer.feeRate,
|
offer.feeRate,
|
||||||
totalCollateral,
|
totalCollateral,
|
||||||
offer.collateral,
|
offer.collateral,
|
||||||
txId,
|
txId,
|
||||||
payoutAddress,
|
payoutAddress,
|
||||||
contact
|
contact
|
||||||
)
|
)
|
||||||
|
|
||||||
assert(status.state == DLCState.Signed)
|
assert(status.state == DLCState.Signed)
|
||||||
assert(read[DLCStatus](write(status)) == status)
|
assert(read[DLCStatus](write(status)) == status)
|
||||||
assert(read[DLCStatus](
|
assert(
|
||||||
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status)
|
read[DLCStatus](
|
||||||
|
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)
|
||||||
|
) == status
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
it must "have json symmetry in DLCStatus.Broadcasted" in {
|
it must "have json symmetry in DLCStatus.Broadcasted" in {
|
||||||
forAllParallel(NumberGenerator.bool,
|
forAllParallel(
|
||||||
TLVGen.dlcOfferTLV,
|
NumberGenerator.bool,
|
||||||
NumberGenerator.bytevector,
|
TLVGen.dlcOfferTLV,
|
||||||
CryptoGenerators.doubleSha256DigestBE) {
|
NumberGenerator.bytevector,
|
||||||
case (isInit, offerTLV, contractId, fundingTxId) =>
|
CryptoGenerators.doubleSha256DigestBE
|
||||||
val offer = DLCOffer.fromTLV(offerTLV)
|
) { case (isInit, offerTLV, contractId, fundingTxId) =>
|
||||||
|
val offer = DLCOffer.fromTLV(offerTLV)
|
||||||
|
|
||||||
val totalCollateral = offer.contractInfo.totalCollateral
|
val totalCollateral = offer.contractInfo.totalCollateral
|
||||||
|
|
||||||
val payoutAddress = Option.empty[PayoutAddress]
|
val payoutAddress = Option.empty[PayoutAddress]
|
||||||
|
|
||||||
val contact = Option.empty[String]
|
val contact = Option.empty[String]
|
||||||
|
|
||||||
val status =
|
val status =
|
||||||
DLCStatus.Broadcasted(
|
DLCStatus.Broadcasted(
|
||||||
Sha256Digest.empty,
|
Sha256Digest.empty,
|
||||||
isInit,
|
isInit,
|
||||||
TimeUtil.now,
|
TimeUtil.now,
|
||||||
offer.tempContractId,
|
offer.tempContractId,
|
||||||
contractId,
|
contractId,
|
||||||
offer.contractInfo,
|
offer.contractInfo,
|
||||||
offer.timeouts,
|
offer.timeouts,
|
||||||
offer.feeRate,
|
offer.feeRate,
|
||||||
totalCollateral,
|
totalCollateral,
|
||||||
offer.collateral,
|
offer.collateral,
|
||||||
fundingTxId,
|
fundingTxId,
|
||||||
payoutAddress,
|
payoutAddress,
|
||||||
contact
|
contact
|
||||||
)
|
)
|
||||||
|
|
||||||
assert(status.state == DLCState.Broadcasted)
|
assert(status.state == DLCState.Broadcasted)
|
||||||
assert(read[DLCStatus](write(status)) == status)
|
assert(read[DLCStatus](write(status)) == status)
|
||||||
assert(read[DLCStatus](
|
assert(
|
||||||
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status)
|
read[DLCStatus](
|
||||||
|
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)
|
||||||
|
) == status
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
it must "have json symmetry in DLCStatus.Confirmed" in {
|
it must "have json symmetry in DLCStatus.Confirmed" in {
|
||||||
forAllParallel(NumberGenerator.bool,
|
forAllParallel(
|
||||||
TLVGen.dlcOfferTLV,
|
NumberGenerator.bool,
|
||||||
NumberGenerator.bytevector,
|
TLVGen.dlcOfferTLV,
|
||||||
CryptoGenerators.doubleSha256DigestBE) {
|
NumberGenerator.bytevector,
|
||||||
case (isInit, offerTLV, contractId, fundingTxId) =>
|
CryptoGenerators.doubleSha256DigestBE
|
||||||
val offer = DLCOffer.fromTLV(offerTLV)
|
) { case (isInit, offerTLV, contractId, fundingTxId) =>
|
||||||
|
val offer = DLCOffer.fromTLV(offerTLV)
|
||||||
|
|
||||||
val totalCollateral = offer.contractInfo.totalCollateral
|
val totalCollateral = offer.contractInfo.totalCollateral
|
||||||
|
|
||||||
val payoutAddress = Option.empty[PayoutAddress]
|
val payoutAddress = Option.empty[PayoutAddress]
|
||||||
|
|
||||||
val contact = Option.empty[String]
|
val contact = Option.empty[String]
|
||||||
|
|
||||||
val status =
|
val status =
|
||||||
DLCStatus.Confirmed(
|
DLCStatus.Confirmed(
|
||||||
Sha256Digest.empty,
|
Sha256Digest.empty,
|
||||||
isInit,
|
isInit,
|
||||||
TimeUtil.now,
|
TimeUtil.now,
|
||||||
offer.tempContractId,
|
offer.tempContractId,
|
||||||
contractId,
|
contractId,
|
||||||
offer.contractInfo,
|
offer.contractInfo,
|
||||||
offer.timeouts,
|
offer.timeouts,
|
||||||
offer.feeRate,
|
offer.feeRate,
|
||||||
totalCollateral,
|
totalCollateral,
|
||||||
offer.collateral,
|
offer.collateral,
|
||||||
fundingTxId,
|
fundingTxId,
|
||||||
payoutAddress,
|
payoutAddress,
|
||||||
contact
|
contact
|
||||||
)
|
)
|
||||||
|
|
||||||
assert(status.state == DLCState.Confirmed)
|
assert(status.state == DLCState.Confirmed)
|
||||||
assert(read[DLCStatus](write(status)) == status)
|
assert(read[DLCStatus](write(status)) == status)
|
||||||
assert(read[DLCStatus](
|
assert(
|
||||||
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status)
|
read[DLCStatus](
|
||||||
|
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)
|
||||||
|
) == status
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +283,9 @@ class DLCStatusTest extends BitcoinSJvmTest {
|
|||||||
assert(read[DLCStatus](write(status)) == status)
|
assert(read[DLCStatus](write(status)) == status)
|
||||||
assert(
|
assert(
|
||||||
read[DLCStatus](
|
read[DLCStatus](
|
||||||
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status)
|
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)
|
||||||
|
) == status
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,7 +342,9 @@ class DLCStatusTest extends BitcoinSJvmTest {
|
|||||||
assert(read[DLCStatus](write(status)) == status)
|
assert(read[DLCStatus](write(status)) == status)
|
||||||
assert(
|
assert(
|
||||||
read[DLCStatus](
|
read[DLCStatus](
|
||||||
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status)
|
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)
|
||||||
|
) == status
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,7 +395,9 @@ class DLCStatusTest extends BitcoinSJvmTest {
|
|||||||
assert(read[DLCStatus](write(status)) == status)
|
assert(read[DLCStatus](write(status)) == status)
|
||||||
assert(
|
assert(
|
||||||
read[DLCStatus](
|
read[DLCStatus](
|
||||||
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status)
|
write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)
|
||||||
|
) == status
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,8 @@ class SerializedPSBTTest extends BitcoinSUnitTest {
|
|||||||
|
|
||||||
it must "correctly decode a psbt" in {
|
it must "correctly decode a psbt" in {
|
||||||
val psbt = PSBT.fromBase64(
|
val psbt = PSBT.fromBase64(
|
||||||
"cHNidP9Fq2AoiZroZUZZ7/Fl0n4dcF8zKWfpD3QzRcAm1QTxUQzzGnHjM5xU+xYUvYSPokH86tLWHVVmhrOQE2d//fPeu6Px6r0LW2DbYkBubiYldhPvO50/3M0wHtHncJ6w/UmdpFVMt/z1iQfbH9U4bq6iLS930BnOiRlc0KX8DQmDnKFdTdiyceBPOmWKSJT+cR1RIQabSiKY6plO4jkSbZ2yFGMBAP3dAgIAAAABG2Z29d/AhiGmmjjrgO9p0LwwYozRbr404YcnQQ+LTQMEAAAAAAAAAAADGQVGPusCAAD9vwFjVyEDkIsYrb9OJzC2oJUtRDntXxhNo7cZeByTHPkuJeCnAmshA4B9R4qr45hWk4fD3F+0um+wJVmP8kFRyXWflgEYKi61IQMLERF8Yx7x85yRmZyD7888+GENPbV2xACyxsAbEJoZpCEDLfkiP2NbzOWOTrM5qIiGFWLDrAYEoYj+6B/p474XWbQhAuNDwvhwWxJHuG/S7CS/bsk/wr8pR9LzCm8eEEqoQ58NIQPlPMn3Y69Fovcn4cexpU9r1whI0yWZ1OwvYHlsngyAyCECyGo6/HPABsWFUwjKuE+mG57duFkwbk17rug85rd0MCohA8ObOSpT1WPHeKKjc3MwDtFM8xr+LRlrDETYazNJhawyIQNqTHMWXX5dNDAuY71BaXfFF8yoHEaQDnDyNudqgfuMQSEC410iVARHWVmvKpcQUFJJx/H41G2/9sJ5jvRnyYIXwQIhA4APXyr35MW/4PPuMRtYg+caUGFqk+12x9wW+JFxHqnwIQMiS1b6HfL93efBgysG0PrlMPwA7eKMSFexdnOGHhOQP1yuZwXdzsmnALF1dqkUCzczWAtdSewwYE3SNlcLhnxJInGIrGjelDmdMwkAABYAFO26WaDgWxcVeSe4lfoysDTitaKJp/r3t2YNAAC4Y1IhA6WEMWgMOWjUk1FZvxYDTRvyVZKDWeCKsBvgJruAngCOIQKeg5DPhM1ghA26JAP1gvhyZ7K/Z2ttavmOd7AyFv2OyyEDjgniAeDz5qiX/5tyDxMJcyMN4yRoYXZwfFgT9x6iKqghAxmojRQWODhnuwBaEtxJHK9AlJXUkPjIOs4o08raE5zfVK5nBF6KYiOxdSEDvbxvoF42LUei1lcblCHsUzeXo7Wr1zKxw5agIRZVWqysaAAAAAAAAQMEggAAAAAAA6jMPk3fqYXY2pAV+YsGMMB2CAwXDBpwMObcmgEz8M0NO07ZYF60Sf8jj0zms7HOPzU3tBtRMROIXzyZreEJOfmqBIZKk6tg78xgjIW8mR+WuQAA")
|
"cHNidP9Fq2AoiZroZUZZ7/Fl0n4dcF8zKWfpD3QzRcAm1QTxUQzzGnHjM5xU+xYUvYSPokH86tLWHVVmhrOQE2d//fPeu6Px6r0LW2DbYkBubiYldhPvO50/3M0wHtHncJ6w/UmdpFVMt/z1iQfbH9U4bq6iLS930BnOiRlc0KX8DQmDnKFdTdiyceBPOmWKSJT+cR1RIQabSiKY6plO4jkSbZ2yFGMBAP3dAgIAAAABG2Z29d/AhiGmmjjrgO9p0LwwYozRbr404YcnQQ+LTQMEAAAAAAAAAAADGQVGPusCAAD9vwFjVyEDkIsYrb9OJzC2oJUtRDntXxhNo7cZeByTHPkuJeCnAmshA4B9R4qr45hWk4fD3F+0um+wJVmP8kFRyXWflgEYKi61IQMLERF8Yx7x85yRmZyD7888+GENPbV2xACyxsAbEJoZpCEDLfkiP2NbzOWOTrM5qIiGFWLDrAYEoYj+6B/p474XWbQhAuNDwvhwWxJHuG/S7CS/bsk/wr8pR9LzCm8eEEqoQ58NIQPlPMn3Y69Fovcn4cexpU9r1whI0yWZ1OwvYHlsngyAyCECyGo6/HPABsWFUwjKuE+mG57duFkwbk17rug85rd0MCohA8ObOSpT1WPHeKKjc3MwDtFM8xr+LRlrDETYazNJhawyIQNqTHMWXX5dNDAuY71BaXfFF8yoHEaQDnDyNudqgfuMQSEC410iVARHWVmvKpcQUFJJx/H41G2/9sJ5jvRnyYIXwQIhA4APXyr35MW/4PPuMRtYg+caUGFqk+12x9wW+JFxHqnwIQMiS1b6HfL93efBgysG0PrlMPwA7eKMSFexdnOGHhOQP1yuZwXdzsmnALF1dqkUCzczWAtdSewwYE3SNlcLhnxJInGIrGjelDmdMwkAABYAFO26WaDgWxcVeSe4lfoysDTitaKJp/r3t2YNAAC4Y1IhA6WEMWgMOWjUk1FZvxYDTRvyVZKDWeCKsBvgJruAngCOIQKeg5DPhM1ghA26JAP1gvhyZ7K/Z2ttavmOd7AyFv2OyyEDjgniAeDz5qiX/5tyDxMJcyMN4yRoYXZwfFgT9x6iKqghAxmojRQWODhnuwBaEtxJHK9AlJXUkPjIOs4o08raE5zfVK5nBF6KYiOxdSEDvbxvoF42LUei1lcblCHsUzeXo7Wr1zKxw5agIRZVWqysaAAAAAAAAQMEggAAAAAAA6jMPk3fqYXY2pAV+YsGMMB2CAwXDBpwMObcmgEz8M0NO07ZYF60Sf8jj0zms7HOPzU3tBtRMROIXzyZreEJOfmqBIZKk6tg78xgjIW8mR+WuQAA"
|
||||||
|
)
|
||||||
|
|
||||||
val tx = psbt.transaction
|
val tx = psbt.transaction
|
||||||
val decoded = SerializedPSBT.decodePSBT(psbt)
|
val decoded = SerializedPSBT.decodePSBT(psbt)
|
||||||
@ -21,10 +22,13 @@ class SerializedPSBTTest extends BitcoinSUnitTest {
|
|||||||
assert(decoded.global.tx == SerializedTransaction.decodeRawTransaction(tx))
|
assert(decoded.global.tx == SerializedTransaction.decodeRawTransaction(tx))
|
||||||
assert(decoded.global.version == UInt32.zero)
|
assert(decoded.global.version == UInt32.zero)
|
||||||
assert(
|
assert(
|
||||||
decoded.global.unknowns == Vector(GlobalPSBTRecord.Unknown(
|
decoded.global.unknowns == Vector(
|
||||||
hex"ab6028899ae8654659eff165d27e1d705f332967e90f743345c026d504f1510cf31a71e3339c54fb1614bd848fa241fcead2d61d556686b39013677ffdf3debba3f1eabd0b",
|
GlobalPSBTRecord.Unknown(
|
||||||
hex"60db62406e6e26257613ef3b9d3fdccd301ed1e7709eb0fd499da4554cb7fcf58907db1fd5386eaea22d2f77d019ce89195cd0a5fc0d09839ca15d4dd8b271e04f3a658a4894fe711d5121069b4a2298ea994ee239126d9db21463"
|
hex"ab6028899ae8654659eff165d27e1d705f332967e90f743345c026d504f1510cf31a71e3339c54fb1614bd848fa241fcead2d61d556686b39013677ffdf3debba3f1eabd0b",
|
||||||
)))
|
hex"60db62406e6e26257613ef3b9d3fdccd301ed1e7709eb0fd499da4554cb7fcf58907db1fd5386eaea22d2f77d019ce89195cd0a5fc0d09839ca15d4dd8b271e04f3a658a4894fe711d5121069b4a2298ea994ee239126d9db21463"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
assert(decoded.inputs.size == 1)
|
assert(decoded.inputs.size == 1)
|
||||||
assert(decoded.inputs.head.bip32Paths.isEmpty)
|
assert(decoded.inputs.head.bip32Paths.isEmpty)
|
||||||
@ -39,7 +43,8 @@ class SerializedPSBTTest extends BitcoinSUnitTest {
|
|||||||
assert(decoded.inputs.head.unknowns.isEmpty)
|
assert(decoded.inputs.head.unknowns.isEmpty)
|
||||||
assert(
|
assert(
|
||||||
decoded.inputs.head.sigHashType
|
decoded.inputs.head.sigHashType
|
||||||
.contains(HashType.sigHashNoneAnyoneCanPay))
|
.contains(HashType.sigHashNoneAnyoneCanPay)
|
||||||
|
)
|
||||||
|
|
||||||
assert(decoded.outputs.size == 3)
|
assert(decoded.outputs.size == 3)
|
||||||
assert(decoded.outputs.head.bip32Paths.isEmpty)
|
assert(decoded.outputs.head.bip32Paths.isEmpty)
|
||||||
@ -50,10 +55,13 @@ class SerializedPSBTTest extends BitcoinSUnitTest {
|
|||||||
assert(decoded.outputs(1).redeemScript.isEmpty)
|
assert(decoded.outputs(1).redeemScript.isEmpty)
|
||||||
assert(decoded.outputs(1).witScript.isEmpty)
|
assert(decoded.outputs(1).witScript.isEmpty)
|
||||||
assert(
|
assert(
|
||||||
decoded.outputs(1).unknowns == Vector(OutputPSBTRecord.Unknown(
|
decoded.outputs(1).unknowns == Vector(
|
||||||
hex"a8cc3e",
|
OutputPSBTRecord.Unknown(
|
||||||
hex"dfa985d8da9015f98b0630c076080c170c1a7030e6dc9a0133f0cd0d3b4ed9605eb449ff238f4ce6b3b1ce3f3537b41b513113885f3c99ade10939f9aa04864a93ab60efcc608c85bc991f96b9"
|
hex"a8cc3e",
|
||||||
)))
|
hex"dfa985d8da9015f98b0630c076080c170c1a7030e6dc9a0133f0cd0d3b4ed9605eb449ff238f4ce6b3b1ce3f3537b41b513113885f3c99ade10939f9aa04864a93ab60efcc608c85bc991f96b9"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
assert(decoded.outputs.last.bip32Paths.isEmpty)
|
assert(decoded.outputs.last.bip32Paths.isEmpty)
|
||||||
assert(decoded.outputs.last.redeemScript.isEmpty)
|
assert(decoded.outputs.last.redeemScript.isEmpty)
|
||||||
assert(decoded.outputs.last.witScript.isEmpty)
|
assert(decoded.outputs.last.witScript.isEmpty)
|
||||||
@ -61,7 +69,8 @@ class SerializedPSBTTest extends BitcoinSUnitTest {
|
|||||||
|
|
||||||
it must "correctly decode a finalized psbt" in {
|
it must "correctly decode a finalized psbt" in {
|
||||||
val psbt = PSBT.fromBase64(
|
val psbt = PSBT.fromBase64(
|
||||||
"cHNidP8BAP1FAQIAAAABGYuEj8rH1dQ8DYG/wIJoOmA07cMG3qUA2joduT39u3QBAAAAAEhEAAAGZi6ggGgAAAAqBOhp5BGydSEDT4d2r4kKjBDT7N3xtlQRvQOoZMDnvl9kcu+Yz0N+zOWsB9sJYW0AAAAmaiSqIantmOy8chX8u/gjrWjoJwzItqupL01TN2d15WGchnbpGlW08zmpugUAAAcEuQUHI7J1tyGqaVkFAABJZCEDd0QjA5VNPMrHshsJ5ToPa6aXjJClUKFubu0Z3qUgGCmsZyEDCXN1QPwcYCN+5PBjESbL9eI3/Fd2SW/L1kOKOJ6lAsqsaMnuN1dBTAAAFlMU75XVn2xj3vMdoWxBKP6yYswBfsdaZnFQHAAAACZqJKohqe2Q60JHII6xx+YrJFTmibrNi7e8pICEfsbYEMYNKhOtMwAAAAAAAQCKAgAAAAAC7ekoBUtTAABQYyED6l4Vptz8do0rhD+X5Xlmyl5Wwi/fM/EwJmYE/LE4XWhnBfcyAqcAsnUhA/spF0dsJg2ZiBFYnA80MM2Pxou90wok6B8hA44T/vJlaKy4YEecR1gAAB4CSESydXapFHyp4KCUiJddycf+SqnAZI21/aJFiKwAAAAAAQdqRzBEAiBMdpIM1wDaIgn1BJarrd27uzx9kcTixUzQMFGbb0KTsQIgBxNIy+cxhoe1Bnxy/X3+ankfNtC4ydjJcMHlxV0MJqOAIQJUjewAnrbEt88DGQklYoDSLGlNS5Z2C6ukMaVGy+p6EgAAAAAAAAA=")
|
"cHNidP8BAP1FAQIAAAABGYuEj8rH1dQ8DYG/wIJoOmA07cMG3qUA2joduT39u3QBAAAAAEhEAAAGZi6ggGgAAAAqBOhp5BGydSEDT4d2r4kKjBDT7N3xtlQRvQOoZMDnvl9kcu+Yz0N+zOWsB9sJYW0AAAAmaiSqIantmOy8chX8u/gjrWjoJwzItqupL01TN2d15WGchnbpGlW08zmpugUAAAcEuQUHI7J1tyGqaVkFAABJZCEDd0QjA5VNPMrHshsJ5ToPa6aXjJClUKFubu0Z3qUgGCmsZyEDCXN1QPwcYCN+5PBjESbL9eI3/Fd2SW/L1kOKOJ6lAsqsaMnuN1dBTAAAFlMU75XVn2xj3vMdoWxBKP6yYswBfsdaZnFQHAAAACZqJKohqe2Q60JHII6xx+YrJFTmibrNi7e8pICEfsbYEMYNKhOtMwAAAAAAAQCKAgAAAAAC7ekoBUtTAABQYyED6l4Vptz8do0rhD+X5Xlmyl5Wwi/fM/EwJmYE/LE4XWhnBfcyAqcAsnUhA/spF0dsJg2ZiBFYnA80MM2Pxou90wok6B8hA44T/vJlaKy4YEecR1gAAB4CSESydXapFHyp4KCUiJddycf+SqnAZI21/aJFiKwAAAAAAQdqRzBEAiBMdpIM1wDaIgn1BJarrd27uzx9kcTixUzQMFGbb0KTsQIgBxNIy+cxhoe1Bnxy/X3+ankfNtC4ydjJcMHlxV0MJqOAIQJUjewAnrbEt88DGQklYoDSLGlNS5Z2C6ukMaVGy+p6EgAAAAAAAAA="
|
||||||
|
)
|
||||||
val tx = psbt.transaction
|
val tx = psbt.transaction
|
||||||
val decoded = SerializedPSBT.decodePSBT(psbt)
|
val decoded = SerializedPSBT.decodePSBT(psbt)
|
||||||
|
|
||||||
|
@ -80,10 +80,10 @@ class AppConfigTest extends BitcoinSAsyncTest {
|
|||||||
for {
|
for {
|
||||||
_ <- walletAppConfig.start()
|
_ <- walletAppConfig.start()
|
||||||
} yield {
|
} yield {
|
||||||
//this should get substituted as all default sqlite
|
// this should get substituted as all default sqlite
|
||||||
//configuration is saved in the "bitcoin-s.sqlite" key
|
// configuration is saved in the "bitcoin-s.sqlite" key
|
||||||
//if in the future we change our default database behavior
|
// if in the future we change our default database behavior
|
||||||
//this test case will need to change to check that the profile is correct
|
// this test case will need to change to check that the profile is correct
|
||||||
assert(walletAppConfig.dbConfig.profile.isInstanceOf[SQLiteProfile])
|
assert(walletAppConfig.dbConfig.profile.isInstanceOf[SQLiteProfile])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,8 +92,8 @@ class AppConfigTest extends BitcoinSAsyncTest {
|
|||||||
val datadir = BitcoinSTestAppConfig.tmpDir()
|
val datadir = BitcoinSTestAppConfig.tmpDir()
|
||||||
System.setProperty("bitcoin-s.wallet.requiredConfirmations", "1")
|
System.setProperty("bitcoin-s.wallet.requiredConfirmations", "1")
|
||||||
|
|
||||||
//need to invalidate the config cache to force typesafe config
|
// need to invalidate the config cache to force typesafe config
|
||||||
//to freshly load all system properties
|
// to freshly load all system properties
|
||||||
ConfigFactory.invalidateCaches()
|
ConfigFactory.invalidateCaches()
|
||||||
|
|
||||||
val walletAppConfig =
|
val walletAppConfig =
|
||||||
|
@ -16,7 +16,8 @@ class AppServerCliJsonTest extends BitcoinSUnitTest {
|
|||||||
assert(parsed1.isSuccess)
|
assert(parsed1.isSuccess)
|
||||||
assert(parsed1.get.walletNameOpt == Some(walletName))
|
assert(parsed1.get.walletNameOpt == Some(walletName))
|
||||||
assert(
|
assert(
|
||||||
parsed1.get.passwordOpt.map(_.toStringSensitive) == Some(aesPassword))
|
parsed1.get.passwordOpt.map(_.toStringSensitive) == Some(aesPassword)
|
||||||
|
)
|
||||||
assert(parsed1.get.bip39PasswordOpt == Some(bip39Password))
|
assert(parsed1.get.bip39PasswordOpt == Some(bip39Password))
|
||||||
|
|
||||||
val arr2 = ujson.Arr(walletName, aesPassword, ujson.Null)
|
val arr2 = ujson.Arr(walletName, aesPassword, ujson.Null)
|
||||||
@ -24,7 +25,8 @@ class AppServerCliJsonTest extends BitcoinSUnitTest {
|
|||||||
assert(parsed2.isSuccess)
|
assert(parsed2.isSuccess)
|
||||||
assert(parsed2.get.walletNameOpt == Some(walletName))
|
assert(parsed2.get.walletNameOpt == Some(walletName))
|
||||||
assert(
|
assert(
|
||||||
parsed2.get.passwordOpt.map(_.toStringSensitive) == Some(aesPassword))
|
parsed2.get.passwordOpt.map(_.toStringSensitive) == Some(aesPassword)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,8 @@ class DLCAcceptJsonSerializerTest extends BitcoinSUnitTest {
|
|||||||
|
|
||||||
it must "have serialization symmetry for a accept json message" in {
|
it must "have serialization symmetry for a accept json message" in {
|
||||||
val accept = upickle.default.read[DLCAcceptTLV](testString)(
|
val accept = upickle.default.read[DLCAcceptTLV](testString)(
|
||||||
Picklers.dlcAcceptTLVPickler)
|
Picklers.dlcAcceptTLVPickler
|
||||||
|
)
|
||||||
val json: String =
|
val json: String =
|
||||||
upickle.default.write(accept)(Picklers.dlcAcceptTLVPickler)
|
upickle.default.write(accept)(Picklers.dlcAcceptTLVPickler)
|
||||||
assert(json == testString.replaceAll("\\s", ""))
|
assert(json == testString.replaceAll("\\s", ""))
|
||||||
|
@ -11,7 +11,8 @@ class SpendingInfoDbSerializerTest extends BitcoinSUnitTest {
|
|||||||
it must "be symmetrical" in {
|
it must "be symmetrical" in {
|
||||||
val original = TransactionTestUtil.spendingInfoDb
|
val original = TransactionTestUtil.spendingInfoDb
|
||||||
val json = upickle.default.writeJs[SpendingInfoDb](original)(
|
val json = upickle.default.writeJs[SpendingInfoDb](original)(
|
||||||
Picklers.spendingInfoDbPickler)
|
Picklers.spendingInfoDbPickler
|
||||||
|
)
|
||||||
|
|
||||||
val parsed = upickle.default.read(json)(Picklers.spendingInfoDbPickler)
|
val parsed = upickle.default.read(json)(Picklers.spendingInfoDbPickler)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ class ServerArgParserTest extends BitcoinSUnitTest {
|
|||||||
it must "handle no command line flags" in {
|
it must "handle no command line flags" in {
|
||||||
val parser = ServerArgParser(Vector.empty)
|
val parser = ServerArgParser(Vector.empty)
|
||||||
|
|
||||||
//config must be empty
|
// config must be empty
|
||||||
assert(parser.toConfig == ConfigFactory.empty())
|
assert(parser.toConfig == ConfigFactory.empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,38 +13,36 @@ import org.bitcoins.core.compat.JavaConverters._
|
|||||||
import scala.util.Properties
|
import scala.util.Properties
|
||||||
import scala.util.matching.Regex
|
import scala.util.matching.Regex
|
||||||
|
|
||||||
/** Everything needed to configure functionality
|
/** Everything needed to configure functionality of bitcoin-s applications is
|
||||||
* of bitcoin-s applications is found in here.
|
* found in here.
|
||||||
*
|
*
|
||||||
* @see [[https://github.com/bitcoin-s/bitcoin-s-core/blob/master/doc/configuration.md `configuration.md`]]
|
* @see
|
||||||
* for more information.
|
* [[https://github.com/bitcoin-s/bitcoin-s-core/blob/master/doc/configuration.md `configuration.md`]]
|
||||||
|
* for more information.
|
||||||
*/
|
*/
|
||||||
abstract class AppConfig extends StartStopAsync[Unit] with BitcoinSLogger {
|
abstract class AppConfig extends StartStopAsync[Unit] with BitcoinSLogger {
|
||||||
|
|
||||||
/** Starts this project.
|
/** Starts this project. After this future resolves, all operations should be
|
||||||
* After this future resolves, all operations should be
|
|
||||||
* able to be performed correctly.
|
* able to be performed correctly.
|
||||||
*
|
*
|
||||||
* Starting may include creating database tables,
|
* Starting may include creating database tables, making directories or files
|
||||||
* making directories or files needed later or
|
* needed later or something else entirely.
|
||||||
* something else entirely.
|
|
||||||
*/
|
*/
|
||||||
override def start(): Future[Unit] = {
|
override def start(): Future[Unit] = {
|
||||||
Future.unit
|
Future.unit
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sub members of AppConfig should override this type with
|
/** Sub members of AppConfig should override this type with the type of
|
||||||
* the type of themselves, ensuring `withOverrides` return
|
* themselves, ensuring `withOverrides` return the correct type
|
||||||
* the correct type
|
|
||||||
*/
|
*/
|
||||||
protected[bitcoins] type ConfigType <: AppConfig
|
protected[bitcoins] type ConfigType <: AppConfig
|
||||||
|
|
||||||
/** Constructor to make a new instance of this config type */
|
/** Constructor to make a new instance of this config type */
|
||||||
protected[bitcoins] def newConfigOfType(
|
protected[bitcoins] def newConfigOfType(
|
||||||
configOverrides: Vector[Config]): ConfigType
|
configOverrides: Vector[Config]
|
||||||
|
): ConfigType
|
||||||
|
|
||||||
/** List of user-provided configs that should
|
/** List of user-provided configs that should override defaults
|
||||||
* override defaults
|
|
||||||
*/
|
*/
|
||||||
protected[bitcoins] def configOverrides: Vector[Config]
|
protected[bitcoins] def configOverrides: Vector[Config]
|
||||||
|
|
||||||
@ -52,14 +50,11 @@ abstract class AppConfig extends StartStopAsync[Unit] with BitcoinSLogger {
|
|||||||
withOverrides(Vector(configOverrides))
|
withOverrides(Vector(configOverrides))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This method returns a new `AppConfig`, where every
|
/** This method returns a new `AppConfig`, where every key under `bitcoin-s`
|
||||||
* key under `bitcoin-s` overrides the configuration
|
* overrides the configuration picked up by other means (the `reference.conf`
|
||||||
* picked up by other means (the `reference.conf`
|
* provided by bitcoin-s and the `application.conf` provided by the user). If
|
||||||
* provided by bitcoin-s and the `application.conf`
|
* you pass in configs with overlapping keys (e.g. several configs with the
|
||||||
* provided by the user). If you pass in configs with
|
* key `bitcoin-s.network`), the latter config overrides the first.
|
||||||
* overlapping keys (e.g. several configs with the key
|
|
||||||
* `bitcoin-s.network`), the latter config overrides the
|
|
||||||
* first.
|
|
||||||
*/
|
*/
|
||||||
def withOverrides(configOverrides: Vector[Config]): ConfigType = {
|
def withOverrides(configOverrides: Vector[Config]): ConfigType = {
|
||||||
val numOverrides = configOverrides.length
|
val numOverrides = configOverrides.length
|
||||||
@ -180,7 +175,8 @@ object AppConfig extends BitcoinSLogger {
|
|||||||
def getBaseConfig(
|
def getBaseConfig(
|
||||||
baseDatadir: Path,
|
baseDatadir: Path,
|
||||||
configFileName: String,
|
configFileName: String,
|
||||||
configOverrides: Vector[Config]): Config = {
|
configOverrides: Vector[Config]
|
||||||
|
): Config = {
|
||||||
val configOptions =
|
val configOptions =
|
||||||
ConfigParseOptions
|
ConfigParseOptions
|
||||||
.defaults()
|
.defaults()
|
||||||
@ -195,7 +191,8 @@ object AppConfig extends BitcoinSLogger {
|
|||||||
|
|
||||||
val withDatadir =
|
val withDatadir =
|
||||||
ConfigFactory.parseString(
|
ConfigFactory.parseString(
|
||||||
s"bitcoin-s.datadir = ${safePathToString(baseDatadir)}")
|
s"bitcoin-s.datadir = ${safePathToString(baseDatadir)}"
|
||||||
|
)
|
||||||
withDatadir.withFallback(config)
|
withDatadir.withFallback(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,8 +234,8 @@ object AppConfig extends BitcoinSLogger {
|
|||||||
|
|
||||||
/** The default data directory
|
/** The default data directory
|
||||||
*
|
*
|
||||||
* TODO: use different directories on Windows and Mac,
|
* TODO: use different directories on Windows and Mac, should probably mimic
|
||||||
* should probably mimic what Bitcoin Core does
|
* what Bitcoin Core does
|
||||||
*/
|
*/
|
||||||
private[bitcoins] lazy val DEFAULT_BITCOIN_S_DATADIR: Path =
|
private[bitcoins] lazy val DEFAULT_BITCOIN_S_DATADIR: Path =
|
||||||
Paths.get(Properties.userHome, ".bitcoin-s")
|
Paths.get(Properties.userHome, ".bitcoin-s")
|
||||||
@ -246,9 +243,8 @@ object AppConfig extends BitcoinSLogger {
|
|||||||
private[bitcoins] lazy val DEFAULT_BITCOIN_S_CONF_FILE: String =
|
private[bitcoins] lazy val DEFAULT_BITCOIN_S_CONF_FILE: String =
|
||||||
"bitcoin-s.conf"
|
"bitcoin-s.conf"
|
||||||
|
|
||||||
/** Matches the default data directory location
|
/** Matches the default data directory location with a network appended, both
|
||||||
* with a network appended,
|
* with and without a trailing `/`
|
||||||
* both with and without a trailing `/`
|
|
||||||
*/
|
*/
|
||||||
private lazy val defaultDatadirRegex: Regex = {
|
private lazy val defaultDatadirRegex: Regex = {
|
||||||
// Fix for windows
|
// Fix for windows
|
||||||
@ -257,8 +253,8 @@ object AppConfig extends BitcoinSLogger {
|
|||||||
(home + "/.bitcoin-s/(testnet3|mainnet|regtest)/?$").r
|
(home + "/.bitcoin-s/(testnet3|mainnet|regtest)/?$").r
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Throws if the encountered datadir is the default one. Useful
|
/** Throws if the encountered datadir is the default one. Useful in tests, to
|
||||||
* in tests, to make sure you don't blow up important data.
|
* make sure you don't blow up important data.
|
||||||
*/
|
*/
|
||||||
private[bitcoins] def throwIfDefaultDatadir(config: AppConfig): Unit = {
|
private[bitcoins] def throwIfDefaultDatadir(config: AppConfig): Unit = {
|
||||||
val datadirStr = config.datadir.toString()
|
val datadirStr = config.datadir.toString()
|
||||||
|
@ -5,7 +5,10 @@ import com.typesafe.config.{Config, ConfigFactory}
|
|||||||
import java.nio.file.{Path, Paths}
|
import java.nio.file.{Path, Paths}
|
||||||
import scala.concurrent.ExecutionContext
|
import scala.concurrent.ExecutionContext
|
||||||
|
|
||||||
/** @tparam I - the implicit argument. This is usually an execution context or an actor system */
|
/** @tparam I
|
||||||
|
* \- the implicit argument. This is usually an execution context or an actor
|
||||||
|
* system
|
||||||
|
*/
|
||||||
trait AppConfigFactoryBase[C <: AppConfig, I] {
|
trait AppConfigFactoryBase[C <: AppConfig, I] {
|
||||||
def moduleName: String
|
def moduleName: String
|
||||||
|
|
||||||
@ -18,13 +21,15 @@ trait AppConfigFactoryBase[C <: AppConfig, I] {
|
|||||||
fromConfig(ConfigFactory.load())
|
fromConfig(ConfigFactory.load())
|
||||||
}
|
}
|
||||||
|
|
||||||
def fromDefaultDatadir(confs: Vector[Config] = Vector.empty)(implicit
|
def fromDefaultDatadir(
|
||||||
i: I): C = {
|
confs: Vector[Config] = Vector.empty
|
||||||
|
)(implicit i: I): C = {
|
||||||
fromDatadir(AppConfig.DEFAULT_BITCOIN_S_DATADIR, confs)
|
fromDatadir(AppConfig.DEFAULT_BITCOIN_S_DATADIR, confs)
|
||||||
}
|
}
|
||||||
|
|
||||||
def fromDatadir(datadir: Path, confs: Vector[Config] = Vector.empty)(implicit
|
def fromDatadir(datadir: Path, confs: Vector[Config] = Vector.empty)(implicit
|
||||||
i: I): C
|
i: I
|
||||||
|
): C
|
||||||
}
|
}
|
||||||
|
|
||||||
trait AppConfigFactory[C <: AppConfig]
|
trait AppConfigFactory[C <: AppConfig]
|
||||||
|
@ -12,17 +12,20 @@ object FileUtil extends BitcoinSLogger {
|
|||||||
|
|
||||||
/** Zips the [[directory]] into a zip file and then stores it at [[target]]
|
/** Zips the [[directory]] into a zip file and then stores it at [[target]]
|
||||||
*
|
*
|
||||||
* @see https://www.quickprogrammingtips.com/java/how-to-zip-a-folder-in-java.html
|
* @see
|
||||||
|
* https://www.quickprogrammingtips.com/java/how-to-zip-a-folder-in-java.html
|
||||||
*/
|
*/
|
||||||
def zipDirectory(
|
def zipDirectory(
|
||||||
source: Path,
|
source: Path,
|
||||||
target: Path,
|
target: Path,
|
||||||
fileNameFilter: Vector[Regex] = Vector.empty): Path = {
|
fileNameFilter: Vector[Regex] = Vector.empty
|
||||||
|
): Path = {
|
||||||
require(
|
require(
|
||||||
!Files.exists(target),
|
!Files.exists(target),
|
||||||
s"Cannot overwrite existing target directory=${target.toAbsolutePath}")
|
s"Cannot overwrite existing target directory=${target.toAbsolutePath}"
|
||||||
|
)
|
||||||
|
|
||||||
//create directories for target if they DNE
|
// create directories for target if they DNE
|
||||||
Files.createDirectories(target.getParent)
|
Files.createDirectories(target.getParent)
|
||||||
|
|
||||||
val zos = new ZipOutputStream(new FileOutputStream(target.toFile))
|
val zos = new ZipOutputStream(new FileOutputStream(target.toFile))
|
||||||
@ -33,16 +36,18 @@ object FileUtil extends BitcoinSLogger {
|
|||||||
@throws[IOException]
|
@throws[IOException]
|
||||||
override def visitFile(
|
override def visitFile(
|
||||||
file: Path,
|
file: Path,
|
||||||
attrs: BasicFileAttributes): FileVisitResult = {
|
attrs: BasicFileAttributes
|
||||||
|
): FileVisitResult = {
|
||||||
if (
|
if (
|
||||||
fileNameFilter.exists(reg =>
|
fileNameFilter
|
||||||
file.toAbsolutePath.toString.matches(reg.regex))
|
.exists(reg => file.toAbsolutePath.toString.matches(reg.regex))
|
||||||
) {
|
) {
|
||||||
logger.info(s"Skipping ${file.toAbsolutePath} for zip")
|
logger.info(s"Skipping ${file.toAbsolutePath} for zip")
|
||||||
FileVisitResult.CONTINUE
|
FileVisitResult.CONTINUE
|
||||||
} else {
|
} else {
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Zipping file=${file.toAbsolutePath} to ${target.toAbsolutePath}")
|
s"Zipping file=${file.toAbsolutePath} to ${target.toAbsolutePath}"
|
||||||
|
)
|
||||||
zos.putNextEntry(new ZipEntry(source.relativize(file).toString))
|
zos.putNextEntry(new ZipEntry(source.relativize(file).toString))
|
||||||
Files.copy(file, zos)
|
Files.copy(file, zos)
|
||||||
zos.closeEntry()
|
zos.closeEntry()
|
||||||
@ -63,24 +68,27 @@ object FileUtil extends BitcoinSLogger {
|
|||||||
def copyDirectory(
|
def copyDirectory(
|
||||||
source: Path,
|
source: Path,
|
||||||
target: Path,
|
target: Path,
|
||||||
fileNameFilter: Vector[Regex] = Vector.empty): Path = {
|
fileNameFilter: Vector[Regex] = Vector.empty
|
||||||
|
): Path = {
|
||||||
Files.walkFileTree(
|
Files.walkFileTree(
|
||||||
source,
|
source,
|
||||||
new SimpleFileVisitor[Path]() {
|
new SimpleFileVisitor[Path]() {
|
||||||
@throws[IOException]
|
@throws[IOException]
|
||||||
override def visitFile(
|
override def visitFile(
|
||||||
file: Path,
|
file: Path,
|
||||||
attrs: BasicFileAttributes): FileVisitResult = {
|
attrs: BasicFileAttributes
|
||||||
|
): FileVisitResult = {
|
||||||
if (
|
if (
|
||||||
fileNameFilter.exists(reg =>
|
fileNameFilter
|
||||||
file.toAbsolutePath.toString.matches(reg.regex))
|
.exists(reg => file.toAbsolutePath.toString.matches(reg.regex))
|
||||||
) {
|
) {
|
||||||
logger.info(s"Skipping ${file.toAbsolutePath} for copy")
|
logger.info(s"Skipping ${file.toAbsolutePath} for copy")
|
||||||
FileVisitResult.CONTINUE
|
FileVisitResult.CONTINUE
|
||||||
} else {
|
} else {
|
||||||
val targetPath = target.resolve(source.relativize(file))
|
val targetPath = target.resolve(source.relativize(file))
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Copying file=${file.toAbsolutePath} to ${targetPath.toAbsolutePath}")
|
s"Copying file=${file.toAbsolutePath} to ${targetPath.toAbsolutePath}"
|
||||||
|
)
|
||||||
Files.createDirectories(targetPath.getParent)
|
Files.createDirectories(targetPath.getParent)
|
||||||
Files.copy(file, targetPath)
|
Files.copy(file, targetPath)
|
||||||
logger.info(s"Done copying file=${file.toAbsolutePath}")
|
logger.info(s"Done copying file=${file.toAbsolutePath}")
|
||||||
@ -100,14 +108,16 @@ object FileUtil extends BitcoinSLogger {
|
|||||||
new SimpleFileVisitor[Path] {
|
new SimpleFileVisitor[Path] {
|
||||||
override def visitFile(
|
override def visitFile(
|
||||||
file: Path,
|
file: Path,
|
||||||
attrs: BasicFileAttributes): FileVisitResult = {
|
attrs: BasicFileAttributes
|
||||||
|
): FileVisitResult = {
|
||||||
Files.delete(file)
|
Files.delete(file)
|
||||||
FileVisitResult.CONTINUE
|
FileVisitResult.CONTINUE
|
||||||
}
|
}
|
||||||
|
|
||||||
override def postVisitDirectory(
|
override def postVisitDirectory(
|
||||||
dir: Path,
|
dir: Path,
|
||||||
exc: IOException): FileVisitResult = {
|
exc: IOException
|
||||||
|
): FileVisitResult = {
|
||||||
Files.delete(dir)
|
Files.delete(dir)
|
||||||
FileVisitResult.CONTINUE
|
FileVisitResult.CONTINUE
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,8 @@ case class BitcoinSServerInfo(
|
|||||||
blockHash: DoubleSha256DigestBE,
|
blockHash: DoubleSha256DigestBE,
|
||||||
torStarted: Boolean,
|
torStarted: Boolean,
|
||||||
syncing: Boolean,
|
syncing: Boolean,
|
||||||
isInitialBlockDownload: Boolean) {
|
isInitialBlockDownload: Boolean
|
||||||
|
) {
|
||||||
|
|
||||||
lazy val toJson: Value = {
|
lazy val toJson: Value = {
|
||||||
Obj(
|
Obj(
|
||||||
@ -38,11 +39,13 @@ object BitcoinSServerInfo {
|
|||||||
val sync = obj(PicklerKeys.syncKey).bool
|
val sync = obj(PicklerKeys.syncKey).bool
|
||||||
val isIBD = obj(PicklerKeys.isInitialBlockDownload).bool
|
val isIBD = obj(PicklerKeys.isInitialBlockDownload).bool
|
||||||
|
|
||||||
BitcoinSServerInfo(network = network,
|
BitcoinSServerInfo(
|
||||||
blockHeight = height,
|
network = network,
|
||||||
blockHash = blockHash,
|
blockHeight = height,
|
||||||
torStarted = torStarted,
|
blockHash = blockHash,
|
||||||
syncing = sync,
|
torStarted = torStarted,
|
||||||
isInitialBlockDownload = isIBD)
|
syncing = sync,
|
||||||
|
isInitialBlockDownload = isIBD
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ import scodec.bits.ByteVector
|
|||||||
case class SerializedPSBT(
|
case class SerializedPSBT(
|
||||||
global: SerializedPSBTGlobalMap,
|
global: SerializedPSBTGlobalMap,
|
||||||
inputs: Vector[SerializedPSBTInputMap],
|
inputs: Vector[SerializedPSBTInputMap],
|
||||||
outputs: Vector[SerializedPSBTOutputMap]) {
|
outputs: Vector[SerializedPSBTOutputMap]
|
||||||
|
) {
|
||||||
val toJson: JsValue = Json.toJson(this)
|
val toJson: JsValue = Json.toJson(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,7 +23,8 @@ case class SerializedPSBTGlobalMap(
|
|||||||
tx: SerializedTransaction,
|
tx: SerializedTransaction,
|
||||||
version: UInt32,
|
version: UInt32,
|
||||||
xpubs: Option[Vector[ExtPublicKey]],
|
xpubs: Option[Vector[ExtPublicKey]],
|
||||||
unknowns: Vector[GlobalPSBTRecord.Unknown])
|
unknowns: Vector[GlobalPSBTRecord.Unknown]
|
||||||
|
)
|
||||||
|
|
||||||
case class SerializedPSBTInputMap(
|
case class SerializedPSBTInputMap(
|
||||||
nonWitnessUtxo: Option[SerializedTransaction],
|
nonWitnessUtxo: Option[SerializedTransaction],
|
||||||
@ -35,13 +37,15 @@ case class SerializedPSBTInputMap(
|
|||||||
finalizedScriptSig: Option[Vector[ScriptToken]],
|
finalizedScriptSig: Option[Vector[ScriptToken]],
|
||||||
finalizedScriptWitness: Option[SerializedTransactionWitness],
|
finalizedScriptWitness: Option[SerializedTransactionWitness],
|
||||||
proofOfReservesCommitment: Option[ByteVector],
|
proofOfReservesCommitment: Option[ByteVector],
|
||||||
unknowns: Vector[InputPSBTRecord.Unknown])
|
unknowns: Vector[InputPSBTRecord.Unknown]
|
||||||
|
)
|
||||||
|
|
||||||
case class SerializedPSBTOutputMap(
|
case class SerializedPSBTOutputMap(
|
||||||
redeemScript: Option[Vector[ScriptToken]],
|
redeemScript: Option[Vector[ScriptToken]],
|
||||||
witScript: Option[Vector[ScriptToken]],
|
witScript: Option[Vector[ScriptToken]],
|
||||||
bip32Paths: Option[Vector[OutputPSBTRecord.BIP32DerivationPath]],
|
bip32Paths: Option[Vector[OutputPSBTRecord.BIP32DerivationPath]],
|
||||||
unknowns: Vector[OutputPSBTRecord.Unknown])
|
unknowns: Vector[OutputPSBTRecord.Unknown]
|
||||||
|
)
|
||||||
|
|
||||||
object SerializedPSBT {
|
object SerializedPSBT {
|
||||||
|
|
||||||
@ -57,7 +61,8 @@ object SerializedPSBT {
|
|||||||
|
|
||||||
def decodeInputMap(
|
def decodeInputMap(
|
||||||
input: InputPSBTMap,
|
input: InputPSBTMap,
|
||||||
index: Int): SerializedPSBTInputMap = {
|
index: Int
|
||||||
|
): SerializedPSBTInputMap = {
|
||||||
val prevTxOpt = input.nonWitnessOrUnknownUTXOOpt.map(_.transactionSpent)
|
val prevTxOpt = input.nonWitnessOrUnknownUTXOOpt.map(_.transactionSpent)
|
||||||
val nonWitnessUtxo = prevTxOpt.map(decodeRawTransaction)
|
val nonWitnessUtxo = prevTxOpt.map(decodeRawTransaction)
|
||||||
val witnessUtxo = input.witnessUTXOOpt.map(rec =>
|
val witnessUtxo = input.witnessUTXOOpt.map(rec =>
|
||||||
@ -80,17 +85,19 @@ object SerializedPSBT {
|
|||||||
|
|
||||||
val unknowns = input.getRecords(PSBTInputKeyId.UnknownKeyId)
|
val unknowns = input.getRecords(PSBTInputKeyId.UnknownKeyId)
|
||||||
|
|
||||||
SerializedPSBTInputMap(nonWitnessUtxo,
|
SerializedPSBTInputMap(
|
||||||
witnessUtxo,
|
nonWitnessUtxo,
|
||||||
sigsOpt,
|
witnessUtxo,
|
||||||
hashType,
|
sigsOpt,
|
||||||
redeemScript,
|
hashType,
|
||||||
witScript,
|
redeemScript,
|
||||||
bip32PathsOpt,
|
witScript,
|
||||||
finalizedScriptSig,
|
bip32PathsOpt,
|
||||||
finalizedWitScript,
|
finalizedScriptSig,
|
||||||
porCommit,
|
finalizedWitScript,
|
||||||
unknowns)
|
porCommit,
|
||||||
|
unknowns
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def decodeOutputMap(output: OutputPSBTMap): SerializedPSBTOutputMap = {
|
def decodeOutputMap(output: OutputPSBTMap): SerializedPSBTOutputMap = {
|
||||||
|
@ -26,7 +26,8 @@ case class SerializedTransaction(
|
|||||||
weight: Long,
|
weight: Long,
|
||||||
locktime: UInt32,
|
locktime: UInt32,
|
||||||
vin: Vector[SerializedTransactionInput],
|
vin: Vector[SerializedTransactionInput],
|
||||||
vout: Vector[SerializedTransactionOutput]) {
|
vout: Vector[SerializedTransactionOutput]
|
||||||
|
) {
|
||||||
val toJson: JsValue = Json.toJson(this)
|
val toJson: JsValue = Json.toJson(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +46,8 @@ case class SerializedTransactionWitness(
|
|||||||
script: Option[Vector[ScriptToken]],
|
script: Option[Vector[ScriptToken]],
|
||||||
pubKey: Option[ECPublicKeyBytes],
|
pubKey: Option[ECPublicKeyBytes],
|
||||||
signature: Option[ECDigitalSignature],
|
signature: Option[ECDigitalSignature],
|
||||||
stack: Option[Vector[ByteVector]])
|
stack: Option[Vector[ByteVector]]
|
||||||
|
)
|
||||||
|
|
||||||
case class SerializedTransactionOutput(
|
case class SerializedTransactionOutput(
|
||||||
value: BigDecimal,
|
value: BigDecimal,
|
||||||
@ -65,35 +67,43 @@ object SerializedTransaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def decodeRawTransactionWitness(
|
def decodeRawTransactionWitness(
|
||||||
witness: ScriptWitness): Option[SerializedTransactionWitness] = {
|
witness: ScriptWitness
|
||||||
|
): Option[SerializedTransactionWitness] = {
|
||||||
witness match {
|
witness match {
|
||||||
case EmptyScriptWitness => None
|
case EmptyScriptWitness => None
|
||||||
case p2wpkh: P2WPKHWitnessV0 =>
|
case p2wpkh: P2WPKHWitnessV0 =>
|
||||||
Some(
|
Some(
|
||||||
SerializedTransactionWitness(hex = p2wpkh.hex,
|
SerializedTransactionWitness(
|
||||||
scriptType = Some("P2WPKH"),
|
hex = p2wpkh.hex,
|
||||||
script = None,
|
scriptType = Some("P2WPKH"),
|
||||||
pubKey = Some(p2wpkh.pubKey),
|
script = None,
|
||||||
signature = Some(p2wpkh.signature),
|
pubKey = Some(p2wpkh.pubKey),
|
||||||
stack = None))
|
signature = Some(p2wpkh.signature),
|
||||||
|
stack = None
|
||||||
|
)
|
||||||
|
)
|
||||||
case p2wsh: P2WSHWitnessV0 =>
|
case p2wsh: P2WSHWitnessV0 =>
|
||||||
Some(
|
Some(
|
||||||
SerializedTransactionWitness(hex = p2wsh.hex,
|
SerializedTransactionWitness(
|
||||||
scriptType = Some("P2WSH"),
|
hex = p2wsh.hex,
|
||||||
script =
|
scriptType = Some("P2WSH"),
|
||||||
Some(p2wsh.redeemScript.asm.toVector),
|
script = Some(p2wsh.redeemScript.asm.toVector),
|
||||||
pubKey = None,
|
pubKey = None,
|
||||||
signature = None,
|
signature = None,
|
||||||
stack = Some(p2wsh.stack.toVector.tail)))
|
stack = Some(p2wsh.stack.toVector.tail)
|
||||||
|
)
|
||||||
|
)
|
||||||
case taprootWitness: TaprootWitness =>
|
case taprootWitness: TaprootWitness =>
|
||||||
throw new UnsupportedOperationException(
|
throw new UnsupportedOperationException(
|
||||||
s"Taproot not supported, got=$taprootWitness")
|
s"Taproot not supported, got=$taprootWitness"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def decodeTransactionInput(
|
def decodeTransactionInput(
|
||||||
input: TransactionInput,
|
input: TransactionInput,
|
||||||
witnessOpt: Option[ScriptWitness]): SerializedTransactionInput = {
|
witnessOpt: Option[ScriptWitness]
|
||||||
|
): SerializedTransactionInput = {
|
||||||
val decodedWitnessOpt = witnessOpt.flatMap(decodeRawTransactionWitness)
|
val decodedWitnessOpt = witnessOpt.flatMap(decodeRawTransactionWitness)
|
||||||
|
|
||||||
SerializedTransactionInput(
|
SerializedTransactionInput(
|
||||||
@ -108,11 +118,14 @@ object SerializedTransaction {
|
|||||||
|
|
||||||
def decodeTransactionOutput(
|
def decodeTransactionOutput(
|
||||||
output: TransactionOutput,
|
output: TransactionOutput,
|
||||||
index: Int): SerializedTransactionOutput = {
|
index: Int
|
||||||
SerializedTransactionOutput(value = output.value.toBigDecimal,
|
): SerializedTransactionOutput = {
|
||||||
n = UInt32(index),
|
SerializedTransactionOutput(
|
||||||
scriptPubKey = output.scriptPubKey.asm.toVector,
|
value = output.value.toBigDecimal,
|
||||||
hex = output.hex)
|
n = UInt32(index),
|
||||||
|
scriptPubKey = output.scriptPubKey.asm.toVector,
|
||||||
|
hex = output.hex
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def decodeRawTransaction(tx: Transaction): SerializedTransaction = {
|
def decodeRawTransaction(tx: Transaction): SerializedTransaction = {
|
||||||
@ -135,14 +148,16 @@ object SerializedTransaction {
|
|||||||
case wtx: WitnessTransaction => Some(wtx.wTxIdBE)
|
case wtx: WitnessTransaction => Some(wtx.wTxIdBE)
|
||||||
}
|
}
|
||||||
|
|
||||||
SerializedTransaction(txid = tx.txIdBE,
|
SerializedTransaction(
|
||||||
wtxid = wtxIdOpt,
|
txid = tx.txIdBE,
|
||||||
version = tx.version,
|
wtxid = wtxIdOpt,
|
||||||
size = tx.byteSize,
|
version = tx.version,
|
||||||
vsize = tx.vsize,
|
size = tx.byteSize,
|
||||||
weight = tx.weight,
|
vsize = tx.vsize,
|
||||||
locktime = tx.lockTime,
|
weight = tx.weight,
|
||||||
vin = inputs,
|
locktime = tx.lockTime,
|
||||||
vout = outputs)
|
vin = inputs,
|
||||||
|
vout = outputs
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,8 @@ case class DumpTxOutSetResult(
|
|||||||
coins_written: Int,
|
coins_written: Int,
|
||||||
base_hash: DoubleSha256DigestBE,
|
base_hash: DoubleSha256DigestBE,
|
||||||
base_height: Int,
|
base_height: Int,
|
||||||
path: Path)
|
path: Path
|
||||||
extends BlockchainResult
|
) extends BlockchainResult
|
||||||
|
|
||||||
case class GetBlockResult(
|
case class GetBlockResult(
|
||||||
hash: DoubleSha256DigestBE,
|
hash: DoubleSha256DigestBE,
|
||||||
@ -45,8 +45,8 @@ case class GetBlockResult(
|
|||||||
difficulty: BigDecimal,
|
difficulty: BigDecimal,
|
||||||
chainwork: String,
|
chainwork: String,
|
||||||
previousblockhash: Option[DoubleSha256DigestBE],
|
previousblockhash: Option[DoubleSha256DigestBE],
|
||||||
nextblockhash: Option[DoubleSha256DigestBE])
|
nextblockhash: Option[DoubleSha256DigestBE]
|
||||||
extends BlockchainResult
|
) extends BlockchainResult
|
||||||
|
|
||||||
abstract trait GetBlockWithTransactionsResult extends BlockchainResult {
|
abstract trait GetBlockWithTransactionsResult extends BlockchainResult {
|
||||||
def hash: DoubleSha256DigestBE
|
def hash: DoubleSha256DigestBE
|
||||||
@ -87,8 +87,8 @@ case class GetBlockWithTransactionsResultV22(
|
|||||||
difficulty: BigDecimal,
|
difficulty: BigDecimal,
|
||||||
chainwork: String,
|
chainwork: String,
|
||||||
previousblockhash: Option[DoubleSha256DigestBE],
|
previousblockhash: Option[DoubleSha256DigestBE],
|
||||||
nextblockhash: Option[DoubleSha256DigestBE])
|
nextblockhash: Option[DoubleSha256DigestBE]
|
||||||
extends GetBlockWithTransactionsResult
|
) extends GetBlockWithTransactionsResult
|
||||||
|
|
||||||
sealed trait GetBlockChainInfoResult extends BlockchainResult {
|
sealed trait GetBlockChainInfoResult extends BlockchainResult {
|
||||||
def chain: NetworkParameters
|
def chain: NetworkParameters
|
||||||
@ -121,8 +121,8 @@ case class GetBlockChainInfoResultPreV19(
|
|||||||
pruneheight: Option[Int],
|
pruneheight: Option[Int],
|
||||||
softforks: Vector[SoftforkPreV19],
|
softforks: Vector[SoftforkPreV19],
|
||||||
bip9_softforks: Map[String, Bip9SoftforkPreV19],
|
bip9_softforks: Map[String, Bip9SoftforkPreV19],
|
||||||
warnings: String)
|
warnings: String
|
||||||
extends GetBlockChainInfoResult
|
) extends GetBlockChainInfoResult
|
||||||
|
|
||||||
case class GetBlockChainInfoResultPostV19(
|
case class GetBlockChainInfoResultPostV19(
|
||||||
chain: NetworkParameters,
|
chain: NetworkParameters,
|
||||||
@ -138,8 +138,8 @@ case class GetBlockChainInfoResultPostV19(
|
|||||||
pruned: Boolean,
|
pruned: Boolean,
|
||||||
pruneheight: Option[Int],
|
pruneheight: Option[Int],
|
||||||
softforks: Map[String, SoftforkPostV19],
|
softforks: Map[String, SoftforkPostV19],
|
||||||
warnings: String)
|
warnings: String
|
||||||
extends GetBlockChainInfoResult
|
) extends GetBlockChainInfoResult
|
||||||
|
|
||||||
// adds time field removes softforks field
|
// adds time field removes softforks field
|
||||||
case class GetBlockChainInfoResultPostV23(
|
case class GetBlockChainInfoResultPostV23(
|
||||||
@ -156,30 +156,30 @@ case class GetBlockChainInfoResultPostV23(
|
|||||||
size_on_disk: Long,
|
size_on_disk: Long,
|
||||||
pruned: Boolean,
|
pruned: Boolean,
|
||||||
pruneheight: Option[Int],
|
pruneheight: Option[Int],
|
||||||
warnings: String)
|
warnings: String
|
||||||
extends GetBlockChainInfoResult
|
) extends GetBlockChainInfoResult
|
||||||
|
|
||||||
case class SoftforkPreV19(
|
case class SoftforkPreV19(
|
||||||
id: String,
|
id: String,
|
||||||
version: Int,
|
version: Int,
|
||||||
enforce: Option[Map[String, SoftforkProgressPreV19]],
|
enforce: Option[Map[String, SoftforkProgressPreV19]],
|
||||||
reject: SoftforkProgressPreV19)
|
reject: SoftforkProgressPreV19
|
||||||
extends BlockchainResult
|
) extends BlockchainResult
|
||||||
|
|
||||||
case class SoftforkProgressPreV19(
|
case class SoftforkProgressPreV19(
|
||||||
status: Option[Boolean],
|
status: Option[Boolean],
|
||||||
found: Option[Int],
|
found: Option[Int],
|
||||||
required: Option[Int],
|
required: Option[Int],
|
||||||
window: Option[Int])
|
window: Option[Int]
|
||||||
extends BlockchainResult
|
) extends BlockchainResult
|
||||||
|
|
||||||
case class Bip9SoftforkPreV19(
|
case class Bip9SoftforkPreV19(
|
||||||
status: String,
|
status: String,
|
||||||
bit: Option[Int],
|
bit: Option[Int],
|
||||||
startTime: Int,
|
startTime: Int,
|
||||||
timeout: BigInt,
|
timeout: BigInt,
|
||||||
since: Int)
|
since: Int
|
||||||
extends BlockchainResult
|
) extends BlockchainResult
|
||||||
|
|
||||||
sealed trait SoftforkPostV19 extends BlockchainResult
|
sealed trait SoftforkPostV19 extends BlockchainResult
|
||||||
|
|
||||||
@ -194,8 +194,8 @@ case class Bip9SoftforkDetails(
|
|||||||
bit: Option[Int],
|
bit: Option[Int],
|
||||||
start_time: Int,
|
start_time: Int,
|
||||||
timeout: BigInt,
|
timeout: BigInt,
|
||||||
since: Int)
|
since: Int
|
||||||
extends BlockchainResult
|
) extends BlockchainResult
|
||||||
|
|
||||||
case class GetBlockHeaderResult(
|
case class GetBlockHeaderResult(
|
||||||
hash: DoubleSha256DigestBE,
|
hash: DoubleSha256DigestBE,
|
||||||
@ -211,8 +211,8 @@ case class GetBlockHeaderResult(
|
|||||||
difficulty: BigDecimal,
|
difficulty: BigDecimal,
|
||||||
chainwork: String,
|
chainwork: String,
|
||||||
previousblockhash: Option[DoubleSha256DigestBE],
|
previousblockhash: Option[DoubleSha256DigestBE],
|
||||||
nextblockhash: Option[DoubleSha256DigestBE])
|
nextblockhash: Option[DoubleSha256DigestBE]
|
||||||
extends BlockchainResult {
|
) extends BlockchainResult {
|
||||||
|
|
||||||
lazy val blockHeaderDb: BlockHeaderDb = {
|
lazy val blockHeaderDb: BlockHeaderDb = {
|
||||||
val bytes = ByteVector.fromValidHex(chainwork).dropWhile(_ == 0x00).toArray
|
val bytes = ByteVector.fromValidHex(chainwork).dropWhile(_ == 0x00).toArray
|
||||||
@ -222,8 +222,8 @@ case class GetBlockHeaderResult(
|
|||||||
|
|
||||||
def blockHeader: BlockHeader = {
|
def blockHeader: BlockHeader = {
|
||||||
|
|
||||||
//prevblockhash is only empty if we have the genesis block
|
// prevblockhash is only empty if we have the genesis block
|
||||||
//we assume the prevhash of the gensis block is the empty hash
|
// we assume the prevhash of the gensis block is the empty hash
|
||||||
val prevHash = {
|
val prevHash = {
|
||||||
if (height == 0 && previousblockhash.isEmpty) {
|
if (height == 0 && previousblockhash.isEmpty) {
|
||||||
DoubleSha256DigestBE.empty
|
DoubleSha256DigestBE.empty
|
||||||
@ -231,12 +231,14 @@ case class GetBlockHeaderResult(
|
|||||||
previousblockhash.get
|
previousblockhash.get
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BlockHeader(version = Int32(version),
|
BlockHeader(
|
||||||
previousBlockHash = prevHash.flip,
|
version = Int32(version),
|
||||||
merkleRootHash = merkleroot.flip,
|
previousBlockHash = prevHash.flip,
|
||||||
time = time,
|
merkleRootHash = merkleroot.flip,
|
||||||
nBits = bits,
|
time = time,
|
||||||
nonce = nonce)
|
nBits = bits,
|
||||||
|
nonce = nonce
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,8 +246,8 @@ case class ChainTip(
|
|||||||
height: Int,
|
height: Int,
|
||||||
hash: DoubleSha256DigestBE,
|
hash: DoubleSha256DigestBE,
|
||||||
branchlen: Int,
|
branchlen: Int,
|
||||||
status: String)
|
status: String
|
||||||
extends BlockchainResult
|
) extends BlockchainResult
|
||||||
|
|
||||||
case class GetChainTxStatsResult(
|
case class GetChainTxStatsResult(
|
||||||
time: UInt32,
|
time: UInt32,
|
||||||
@ -254,8 +256,8 @@ case class GetChainTxStatsResult(
|
|||||||
window_final_block_height: Option[Int],
|
window_final_block_height: Option[Int],
|
||||||
window_tx_count: Option[Int],
|
window_tx_count: Option[Int],
|
||||||
window_interval: Option[UInt32],
|
window_interval: Option[UInt32],
|
||||||
txrate: Option[BigDecimal])
|
txrate: Option[BigDecimal]
|
||||||
extends BlockchainResult
|
) extends BlockchainResult
|
||||||
|
|
||||||
sealed trait GetMemPoolResult extends BlockchainResult {
|
sealed trait GetMemPoolResult extends BlockchainResult {
|
||||||
def size: Int
|
def size: Int
|
||||||
@ -284,8 +286,8 @@ case class GetMemPoolResultPreV19(
|
|||||||
ancestorfees: Option[Bitcoins],
|
ancestorfees: Option[Bitcoins],
|
||||||
wtxid: DoubleSha256DigestBE,
|
wtxid: DoubleSha256DigestBE,
|
||||||
fees: FeeInfo,
|
fees: FeeInfo,
|
||||||
depends: Vector[DoubleSha256DigestBE])
|
depends: Vector[DoubleSha256DigestBE]
|
||||||
extends GetMemPoolResult
|
) extends GetMemPoolResult
|
||||||
|
|
||||||
case class GetMemPoolResultPostV19(
|
case class GetMemPoolResultPostV19(
|
||||||
vsize: Int,
|
vsize: Int,
|
||||||
@ -301,8 +303,8 @@ case class GetMemPoolResultPostV19(
|
|||||||
ancestorfees: Option[Bitcoins],
|
ancestorfees: Option[Bitcoins],
|
||||||
wtxid: DoubleSha256DigestBE,
|
wtxid: DoubleSha256DigestBE,
|
||||||
fees: FeeInfo,
|
fees: FeeInfo,
|
||||||
depends: Vector[DoubleSha256DigestBE])
|
depends: Vector[DoubleSha256DigestBE]
|
||||||
extends GetMemPoolResult {
|
) extends GetMemPoolResult {
|
||||||
override def size: Int = vsize
|
override def size: Int = vsize
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,8 +319,8 @@ case class GetMemPoolResultPostV23(
|
|||||||
ancestorsize: Int,
|
ancestorsize: Int,
|
||||||
wtxid: DoubleSha256DigestBE,
|
wtxid: DoubleSha256DigestBE,
|
||||||
fees: FeeInfo,
|
fees: FeeInfo,
|
||||||
depends: Vector[DoubleSha256DigestBE])
|
depends: Vector[DoubleSha256DigestBE]
|
||||||
extends GetMemPoolResult {
|
) extends GetMemPoolResult {
|
||||||
override def size: Int = vsize
|
override def size: Int = vsize
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,8 +358,8 @@ case class GetMemPoolEntryResultPreV19(
|
|||||||
ancestorfees: BitcoinFeeUnit,
|
ancestorfees: BitcoinFeeUnit,
|
||||||
wtxid: DoubleSha256DigestBE,
|
wtxid: DoubleSha256DigestBE,
|
||||||
fees: FeeInfo,
|
fees: FeeInfo,
|
||||||
depends: Option[Vector[DoubleSha256DigestBE]])
|
depends: Option[Vector[DoubleSha256DigestBE]]
|
||||||
extends GetMemPoolEntryResult
|
) extends GetMemPoolEntryResult
|
||||||
|
|
||||||
case class GetMemPoolEntryResultPostV19(
|
case class GetMemPoolEntryResultPostV19(
|
||||||
vsize: Int,
|
vsize: Int,
|
||||||
@ -374,8 +376,8 @@ case class GetMemPoolEntryResultPostV19(
|
|||||||
ancestorfees: BitcoinFeeUnit,
|
ancestorfees: BitcoinFeeUnit,
|
||||||
wtxid: DoubleSha256DigestBE,
|
wtxid: DoubleSha256DigestBE,
|
||||||
fees: FeeInfo,
|
fees: FeeInfo,
|
||||||
depends: Option[Vector[DoubleSha256DigestBE]])
|
depends: Option[Vector[DoubleSha256DigestBE]]
|
||||||
extends GetMemPoolEntryResult {
|
) extends GetMemPoolEntryResult {
|
||||||
override def size: Int = vsize
|
override def size: Int = vsize
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,8 +392,8 @@ case class GetMemPoolEntryResultPostV23(
|
|||||||
ancestorsize: Int,
|
ancestorsize: Int,
|
||||||
wtxid: DoubleSha256DigestBE,
|
wtxid: DoubleSha256DigestBE,
|
||||||
fees: FeeInfo,
|
fees: FeeInfo,
|
||||||
depends: Option[Vector[DoubleSha256DigestBE]])
|
depends: Option[Vector[DoubleSha256DigestBE]]
|
||||||
extends GetMemPoolEntryResult {
|
) extends GetMemPoolEntryResult {
|
||||||
override def size: Int = vsize
|
override def size: Int = vsize
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,8 +403,8 @@ case class GetMemPoolInfoResult(
|
|||||||
usage: Int,
|
usage: Int,
|
||||||
maxmempool: Int,
|
maxmempool: Int,
|
||||||
mempoolminfee: BitcoinFeeUnit,
|
mempoolminfee: BitcoinFeeUnit,
|
||||||
minrelaytxfee: Bitcoins)
|
minrelaytxfee: Bitcoins
|
||||||
extends BlockchainResult
|
) extends BlockchainResult
|
||||||
|
|
||||||
sealed abstract trait GetTxOutResult extends BlockchainResult {
|
sealed abstract trait GetTxOutResult extends BlockchainResult {
|
||||||
def bestblock: DoubleSha256DigestBE
|
def bestblock: DoubleSha256DigestBE
|
||||||
@ -417,8 +419,8 @@ case class GetTxOutResultV22(
|
|||||||
confirmations: Int,
|
confirmations: Int,
|
||||||
value: Bitcoins,
|
value: Bitcoins,
|
||||||
scriptPubKey: RpcScriptPubKeyPostV22,
|
scriptPubKey: RpcScriptPubKeyPostV22,
|
||||||
coinbase: Boolean)
|
coinbase: Boolean
|
||||||
extends GetTxOutResult
|
) extends GetTxOutResult
|
||||||
|
|
||||||
case class GetTxOutSetInfoResult(
|
case class GetTxOutSetInfoResult(
|
||||||
height: Int,
|
height: Int,
|
||||||
@ -428,17 +430,18 @@ case class GetTxOutSetInfoResult(
|
|||||||
bogosize: Int,
|
bogosize: Int,
|
||||||
hash_serialized_2: DoubleSha256DigestBE,
|
hash_serialized_2: DoubleSha256DigestBE,
|
||||||
disk_size: Int,
|
disk_size: Int,
|
||||||
total_amount: Bitcoins)
|
total_amount: Bitcoins
|
||||||
extends BlockchainResult
|
) extends BlockchainResult
|
||||||
|
|
||||||
case class GetBlockFilterResult(
|
case class GetBlockFilterResult(
|
||||||
filter: GolombFilter,
|
filter: GolombFilter,
|
||||||
header: DoubleSha256DigestBE)
|
header: DoubleSha256DigestBE
|
||||||
extends BlockchainResult {
|
) extends BlockchainResult {
|
||||||
|
|
||||||
def filterDb(
|
def filterDb(
|
||||||
height: Int,
|
height: Int,
|
||||||
blockHashBE: DoubleSha256DigestBE): CompactFilterDb = {
|
blockHashBE: DoubleSha256DigestBE
|
||||||
|
): CompactFilterDb = {
|
||||||
CompactFilterDbHelper.fromGolombFilter(filter, blockHashBE, height)
|
CompactFilterDbHelper.fromGolombFilter(filter, blockHashBE, height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -446,7 +449,8 @@ case class GetBlockFilterResult(
|
|||||||
case class GetTxSpendingPrevOutResult(
|
case class GetTxSpendingPrevOutResult(
|
||||||
txid: DoubleSha256DigestBE,
|
txid: DoubleSha256DigestBE,
|
||||||
vout: Int,
|
vout: Int,
|
||||||
spendingtxid: Option[DoubleSha256DigestBE]) {
|
spendingtxid: Option[DoubleSha256DigestBE]
|
||||||
|
) {
|
||||||
def outpoint: TransactionOutPoint = TransactionOutPoint(txid, UInt32(vout))
|
def outpoint: TransactionOutPoint = TransactionOutPoint(txid, UInt32(vout))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ sealed abstract class NetworkResult
|
|||||||
case class Node(
|
case class Node(
|
||||||
addednode: URI,
|
addednode: URI,
|
||||||
connected: Option[Boolean],
|
connected: Option[Boolean],
|
||||||
addresses: Option[Vector[NodeAddress]])
|
addresses: Option[Vector[NodeAddress]]
|
||||||
extends NetworkResult
|
) extends NetworkResult
|
||||||
|
|
||||||
case class NodeAddress(address: URI, connected: String) extends NetworkResult
|
case class NodeAddress(address: URI, connected: String) extends NetworkResult
|
||||||
|
|
||||||
@ -22,8 +22,8 @@ case class GetNetTotalsResult(
|
|||||||
totalbytesrecv: Int,
|
totalbytesrecv: Int,
|
||||||
totalbytessent: Int,
|
totalbytessent: Int,
|
||||||
timemillis: UInt64,
|
timemillis: UInt64,
|
||||||
uploadtarget: NetTarget)
|
uploadtarget: NetTarget
|
||||||
extends NetworkResult
|
) extends NetworkResult
|
||||||
|
|
||||||
case class NetTarget(
|
case class NetTarget(
|
||||||
timeframe: UInt32,
|
timeframe: UInt32,
|
||||||
@ -31,8 +31,8 @@ case class NetTarget(
|
|||||||
target_reached: Boolean,
|
target_reached: Boolean,
|
||||||
serve_historical_blocks: Boolean,
|
serve_historical_blocks: Boolean,
|
||||||
bytes_left_in_cycle: Int,
|
bytes_left_in_cycle: Int,
|
||||||
time_left_in_cycle: UInt32)
|
time_left_in_cycle: UInt32
|
||||||
extends NetworkResult
|
) extends NetworkResult
|
||||||
|
|
||||||
trait GetNetworkInfoResult extends NetworkResult {
|
trait GetNetworkInfoResult extends NetworkResult {
|
||||||
def version: Int
|
def version: Int
|
||||||
@ -65,8 +65,8 @@ case class GetNetworkInfoResultPreV21(
|
|||||||
relayfee: Bitcoins,
|
relayfee: Bitcoins,
|
||||||
incrementalfee: Bitcoins,
|
incrementalfee: Bitcoins,
|
||||||
localaddresses: Vector[NetworkAddress],
|
localaddresses: Vector[NetworkAddress],
|
||||||
warnings: String)
|
warnings: String
|
||||||
extends GetNetworkInfoResult
|
) extends GetNetworkInfoResult
|
||||||
|
|
||||||
case class GetNetworkInfoResultPostV21(
|
case class GetNetworkInfoResultPostV21(
|
||||||
version: Int,
|
version: Int,
|
||||||
@ -84,16 +84,16 @@ case class GetNetworkInfoResultPostV21(
|
|||||||
relayfee: Bitcoins,
|
relayfee: Bitcoins,
|
||||||
incrementalfee: Bitcoins,
|
incrementalfee: Bitcoins,
|
||||||
localaddresses: Vector[NetworkAddress],
|
localaddresses: Vector[NetworkAddress],
|
||||||
warnings: String)
|
warnings: String
|
||||||
extends GetNetworkInfoResult
|
) extends GetNetworkInfoResult
|
||||||
|
|
||||||
case class Network(
|
case class Network(
|
||||||
name: String,
|
name: String,
|
||||||
limited: Boolean,
|
limited: Boolean,
|
||||||
reachable: Boolean,
|
reachable: Boolean,
|
||||||
proxy: String,
|
proxy: String,
|
||||||
proxy_randomize_credentials: Boolean)
|
proxy_randomize_credentials: Boolean
|
||||||
extends NetworkResult
|
) extends NetworkResult
|
||||||
|
|
||||||
case class NetworkAddress(address: String, port: Int, score: Int)
|
case class NetworkAddress(address: String, port: Int, score: Int)
|
||||||
extends NetworkResult
|
extends NetworkResult
|
||||||
@ -127,8 +127,8 @@ case class PeerPostV21(
|
|||||||
inflight: Vector[Int],
|
inflight: Vector[Int],
|
||||||
bytessent_per_msg: Map[String, Int],
|
bytessent_per_msg: Map[String, Int],
|
||||||
bytesrecv_per_msg: Map[String, Int],
|
bytesrecv_per_msg: Map[String, Int],
|
||||||
minfeefilter: Option[SatoshisPerKiloByte])
|
minfeefilter: Option[SatoshisPerKiloByte]
|
||||||
extends Peer {
|
) extends Peer {
|
||||||
override val addnode: Boolean = connection_type == "manual"
|
override val addnode: Boolean = connection_type == "manual"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,8 +148,8 @@ case class PeerV22(
|
|||||||
minfeefilter: Option[SatoshisPerKiloByte],
|
minfeefilter: Option[SatoshisPerKiloByte],
|
||||||
bip152_hb_to: Boolean,
|
bip152_hb_to: Boolean,
|
||||||
bip152_hb_from: Boolean,
|
bip152_hb_from: Boolean,
|
||||||
permissions: Vector[String])
|
permissions: Vector[String]
|
||||||
extends Peer {
|
) extends Peer {
|
||||||
override val addnode: Boolean = connection_type == "manual"
|
override val addnode: Boolean = connection_type == "manual"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,8 +186,8 @@ case class PeerNetworkInfoPreV21(
|
|||||||
timeoffset: Int,
|
timeoffset: Int,
|
||||||
pingtime: Option[BigDecimal],
|
pingtime: Option[BigDecimal],
|
||||||
minping: Option[BigDecimal],
|
minping: Option[BigDecimal],
|
||||||
pingwait: Option[BigDecimal])
|
pingwait: Option[BigDecimal]
|
||||||
extends PeerNetworkInfo
|
) extends PeerNetworkInfo
|
||||||
|
|
||||||
case class PeerNetworkInfoPostV21(
|
case class PeerNetworkInfoPostV21(
|
||||||
addr: URI,
|
addr: URI,
|
||||||
@ -208,8 +208,8 @@ case class PeerNetworkInfoPostV21(
|
|||||||
timeoffset: Int,
|
timeoffset: Int,
|
||||||
pingtime: Option[BigDecimal],
|
pingtime: Option[BigDecimal],
|
||||||
minping: Option[BigDecimal],
|
minping: Option[BigDecimal],
|
||||||
pingwait: Option[BigDecimal])
|
pingwait: Option[BigDecimal]
|
||||||
extends PeerNetworkInfo
|
) extends PeerNetworkInfo
|
||||||
|
|
||||||
trait NodeBan extends NetworkResult {
|
trait NodeBan extends NetworkResult {
|
||||||
def address: URI
|
def address: URI
|
||||||
@ -221,8 +221,8 @@ case class NodeBanPreV20(
|
|||||||
address: URI,
|
address: URI,
|
||||||
banned_until: UInt32,
|
banned_until: UInt32,
|
||||||
ban_created: UInt32,
|
ban_created: UInt32,
|
||||||
ban_reason: String)
|
ban_reason: String
|
||||||
extends NodeBan
|
) extends NodeBan
|
||||||
|
|
||||||
case class NodeBanPostV22(
|
case class NodeBanPostV22(
|
||||||
address: URI,
|
address: URI,
|
||||||
|
@ -40,8 +40,8 @@ case class GetBlockTemplateResult(
|
|||||||
weightlimit: Int,
|
weightlimit: Int,
|
||||||
curtime: UInt32,
|
curtime: UInt32,
|
||||||
bits: String, // What should this be?
|
bits: String, // What should this be?
|
||||||
height: Int)
|
height: Int
|
||||||
extends OtherResult
|
) extends OtherResult
|
||||||
|
|
||||||
case class BlockTransaction(
|
case class BlockTransaction(
|
||||||
data: Transaction,
|
data: Transaction,
|
||||||
@ -51,8 +51,8 @@ case class BlockTransaction(
|
|||||||
fee: Satoshis,
|
fee: Satoshis,
|
||||||
sigops: Int,
|
sigops: Int,
|
||||||
weight: Int,
|
weight: Int,
|
||||||
required: Option[Boolean])
|
required: Option[Boolean]
|
||||||
extends OtherResult
|
) extends OtherResult
|
||||||
|
|
||||||
case class GetMiningInfoResult(
|
case class GetMiningInfoResult(
|
||||||
blocks: Int,
|
blocks: Int,
|
||||||
@ -62,8 +62,8 @@ case class GetMiningInfoResult(
|
|||||||
networkhashps: BigDecimal,
|
networkhashps: BigDecimal,
|
||||||
pooledtx: Int,
|
pooledtx: Int,
|
||||||
chain: String,
|
chain: String,
|
||||||
warnings: String)
|
warnings: String
|
||||||
extends OtherResult
|
) extends OtherResult
|
||||||
|
|
||||||
case class GetMemoryInfoResult(locked: MemoryManager) extends OtherResult
|
case class GetMemoryInfoResult(locked: MemoryManager) extends OtherResult
|
||||||
|
|
||||||
@ -75,14 +75,12 @@ case class MemoryManager(
|
|||||||
total: Int,
|
total: Int,
|
||||||
locked: Int,
|
locked: Int,
|
||||||
chunks_used: Int,
|
chunks_used: Int,
|
||||||
chunks_free: Int)
|
chunks_free: Int
|
||||||
extends OtherResult
|
) extends OtherResult
|
||||||
|
|
||||||
/** @note This is defined as a trait
|
/** @note
|
||||||
* and not just a raw case class
|
* This is defined as a trait and not just a raw case class (as is done in
|
||||||
* (as is done in other RPC return
|
* other RPC return values) in order to make it possible to deprecate fields.
|
||||||
* values) in order to make it possible
|
|
||||||
* to deprecate fields.
|
|
||||||
*/
|
*/
|
||||||
trait ValidateAddressResult {
|
trait ValidateAddressResult {
|
||||||
|
|
||||||
@ -149,14 +147,14 @@ case class ValidateAddressResultImpl(
|
|||||||
hdmasterkeyid: Option[Sha256Hash160Digest],
|
hdmasterkeyid: Option[Sha256Hash160Digest],
|
||||||
ischange: Option[Boolean],
|
ischange: Option[Boolean],
|
||||||
solvable: Option[Boolean],
|
solvable: Option[Boolean],
|
||||||
desc: Option[String])
|
desc: Option[String]
|
||||||
extends ValidateAddressResult
|
) extends ValidateAddressResult
|
||||||
|
|
||||||
case class EstimateSmartFeeResult(
|
case class EstimateSmartFeeResult(
|
||||||
feerate: Option[BitcoinFeeUnit],
|
feerate: Option[BitcoinFeeUnit],
|
||||||
errors: Option[Vector[String]],
|
errors: Option[Vector[String]],
|
||||||
blocks: Int)
|
blocks: Int
|
||||||
extends OtherResult
|
) extends OtherResult
|
||||||
|
|
||||||
case class TestMempoolAcceptResult(
|
case class TestMempoolAcceptResult(
|
||||||
txid: DoubleSha256DigestBE,
|
txid: DoubleSha256DigestBE,
|
||||||
@ -164,17 +162,12 @@ case class TestMempoolAcceptResult(
|
|||||||
rejectReason: Option[String]
|
rejectReason: Option[String]
|
||||||
)
|
)
|
||||||
|
|
||||||
/** sealed trait TestMempoolAcceptResult {
|
/** sealed trait TestMempoolAcceptResult { def txid: DoubleSha256DigestBE def
|
||||||
* def txid: DoubleSha256DigestBE
|
* allowed: Boolean def rejectReason: Option[String] }
|
||||||
* def allowed: Boolean
|
|
||||||
* def rejectReason: Option[String]
|
|
||||||
* }
|
|
||||||
*
|
*
|
||||||
* case class TestMempoolAcceptResultPreV22(
|
* case class TestMempoolAcceptResultPreV22( txid: DoubleSha256DigestBE,
|
||||||
* txid: DoubleSha256DigestBE,
|
* allowed: Boolean, rejectReason: Option[String] ) extends
|
||||||
* allowed: Boolean,
|
* TestMempoolAcceptResult
|
||||||
* rejectReason: Option[String]
|
|
||||||
* ) extends TestMempoolAcceptResult
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
case class FeeInfoTwo(
|
case class FeeInfoTwo(
|
||||||
|
@ -33,8 +33,8 @@ case class RpcTransactionV22(
|
|||||||
locktime: UInt32,
|
locktime: UInt32,
|
||||||
vin: Vector[TransactionInput],
|
vin: Vector[TransactionInput],
|
||||||
vout: Vector[RpcTransactionOutputV22],
|
vout: Vector[RpcTransactionOutputV22],
|
||||||
hex: Option[Transaction])
|
hex: Option[Transaction]
|
||||||
extends RpcTransaction
|
) extends RpcTransaction
|
||||||
|
|
||||||
sealed trait RpcTransactionOutput extends RawTransactionResult {
|
sealed trait RpcTransactionOutput extends RawTransactionResult {
|
||||||
def value: Bitcoins
|
def value: Bitcoins
|
||||||
@ -45,14 +45,14 @@ sealed trait RpcTransactionOutput extends RawTransactionResult {
|
|||||||
case class RpcTransactionOutputPreV22(
|
case class RpcTransactionOutputPreV22(
|
||||||
value: Bitcoins,
|
value: Bitcoins,
|
||||||
n: Int,
|
n: Int,
|
||||||
scriptPubKey: RpcScriptPubKeyPreV22)
|
scriptPubKey: RpcScriptPubKeyPreV22
|
||||||
extends RpcTransactionOutput
|
) extends RpcTransactionOutput
|
||||||
|
|
||||||
case class RpcTransactionOutputV22(
|
case class RpcTransactionOutputV22(
|
||||||
value: Bitcoins,
|
value: Bitcoins,
|
||||||
n: Int,
|
n: Int,
|
||||||
scriptPubKey: RpcScriptPubKeyPostV22)
|
scriptPubKey: RpcScriptPubKeyPostV22
|
||||||
extends RpcTransactionOutput
|
) extends RpcTransactionOutput
|
||||||
|
|
||||||
sealed trait RpcScriptPubKey extends RawTransactionResult {
|
sealed trait RpcScriptPubKey extends RawTransactionResult {
|
||||||
def asm: String
|
def asm: String
|
||||||
@ -66,16 +66,16 @@ case class RpcScriptPubKeyPreV22(
|
|||||||
hex: String,
|
hex: String,
|
||||||
reqSigs: Option[Int],
|
reqSigs: Option[Int],
|
||||||
scriptType: ScriptType,
|
scriptType: ScriptType,
|
||||||
addresses: Option[Vector[BitcoinAddress]])
|
addresses: Option[Vector[BitcoinAddress]]
|
||||||
extends RpcScriptPubKey
|
) extends RpcScriptPubKey
|
||||||
|
|
||||||
case class RpcScriptPubKeyPostV22(
|
case class RpcScriptPubKeyPostV22(
|
||||||
asm: String,
|
asm: String,
|
||||||
hex: String,
|
hex: String,
|
||||||
scriptType: ScriptType,
|
scriptType: ScriptType,
|
||||||
addresses: Option[Vector[BitcoinAddress]],
|
addresses: Option[Vector[BitcoinAddress]],
|
||||||
address: Option[BitcoinAddress])
|
address: Option[BitcoinAddress]
|
||||||
extends RpcScriptPubKey
|
) extends RpcScriptPubKey
|
||||||
|
|
||||||
sealed trait DecodeScriptResult extends RawTransactionResult {
|
sealed trait DecodeScriptResult extends RawTransactionResult {
|
||||||
def asm: String
|
def asm: String
|
||||||
@ -86,14 +86,14 @@ sealed trait DecodeScriptResult extends RawTransactionResult {
|
|||||||
case class DecodeScriptResultV22(
|
case class DecodeScriptResultV22(
|
||||||
asm: String,
|
asm: String,
|
||||||
typeOfScript: Option[ScriptType],
|
typeOfScript: Option[ScriptType],
|
||||||
p2sh: P2SHAddress)
|
p2sh: P2SHAddress
|
||||||
extends DecodeScriptResult
|
) extends DecodeScriptResult
|
||||||
|
|
||||||
case class FundRawTransactionResult(
|
case class FundRawTransactionResult(
|
||||||
hex: Transaction,
|
hex: Transaction,
|
||||||
fee: Bitcoins,
|
fee: Bitcoins,
|
||||||
changepos: Int)
|
changepos: Int
|
||||||
extends RawTransactionResult
|
) extends RawTransactionResult
|
||||||
|
|
||||||
case class SignRawTransactionWithWalletResult(
|
case class SignRawTransactionWithWalletResult(
|
||||||
hex: Transaction,
|
hex: Transaction,
|
||||||
@ -131,8 +131,8 @@ case class GetRawTransactionResultV22(
|
|||||||
blockhash: Option[DoubleSha256DigestBE],
|
blockhash: Option[DoubleSha256DigestBE],
|
||||||
confirmations: Option[Int],
|
confirmations: Option[Int],
|
||||||
time: Option[UInt32],
|
time: Option[UInt32],
|
||||||
blocktime: Option[UInt32])
|
blocktime: Option[UInt32]
|
||||||
extends GetRawTransactionResult
|
) extends GetRawTransactionResult
|
||||||
|
|
||||||
case class GetRawTransactionVin(
|
case class GetRawTransactionVin(
|
||||||
txid: Option[DoubleSha256DigestBE],
|
txid: Option[DoubleSha256DigestBE],
|
||||||
@ -148,16 +148,16 @@ case class GetRawTransactionScriptSig(asm: String, hex: ScriptSignature)
|
|||||||
case class SignRawTransactionResult(
|
case class SignRawTransactionResult(
|
||||||
hex: Transaction,
|
hex: Transaction,
|
||||||
complete: Boolean,
|
complete: Boolean,
|
||||||
errors: Option[Vector[SignRawTransactionError]])
|
errors: Option[Vector[SignRawTransactionError]]
|
||||||
extends RawTransactionResult
|
) extends RawTransactionResult
|
||||||
|
|
||||||
case class SignRawTransactionError(
|
case class SignRawTransactionError(
|
||||||
txid: DoubleSha256DigestBE,
|
txid: DoubleSha256DigestBE,
|
||||||
vout: Int,
|
vout: Int,
|
||||||
scriptSig: ScriptPubKey,
|
scriptSig: ScriptPubKey,
|
||||||
sequence: UInt32,
|
sequence: UInt32,
|
||||||
error: String)
|
error: String
|
||||||
extends RawTransactionResult
|
) extends RawTransactionResult
|
||||||
|
|
||||||
final case class GetRpcInfoResult(
|
final case class GetRpcInfoResult(
|
||||||
active_commands: Vector[RpcCommands]
|
active_commands: Vector[RpcCommands]
|
||||||
@ -165,5 +165,5 @@ final case class GetRpcInfoResult(
|
|||||||
|
|
||||||
final case class RpcCommands(
|
final case class RpcCommands(
|
||||||
method: String,
|
method: String,
|
||||||
duration: FiniteDuration //this time is in microseconds
|
duration: FiniteDuration // this time is in microseconds
|
||||||
) extends RawTransactionResult
|
) extends RawTransactionResult
|
||||||
|
@ -43,7 +43,8 @@ object RpcOpts {
|
|||||||
lockUnspents: Boolean = false,
|
lockUnspents: Boolean = false,
|
||||||
reverseChangeKey: Boolean = true,
|
reverseChangeKey: Boolean = true,
|
||||||
feeRate: Option[Bitcoins] = None,
|
feeRate: Option[Bitcoins] = None,
|
||||||
subtractFeeFromOutputs: Option[Vector[Int]])
|
subtractFeeFromOutputs: Option[Vector[Int]]
|
||||||
|
)
|
||||||
|
|
||||||
sealed abstract class FeeEstimationMode
|
sealed abstract class FeeEstimationMode
|
||||||
|
|
||||||
@ -75,8 +76,9 @@ object RpcOpts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val fundRawTransactionOptionsWrites: Writes[
|
implicit val fundRawTransactionOptionsWrites
|
||||||
FundRawTransactionOptions] = Json.writes[FundRawTransactionOptions]
|
: Writes[FundRawTransactionOptions] =
|
||||||
|
Json.writes[FundRawTransactionOptions]
|
||||||
|
|
||||||
case class SignRawTransactionOutputParameter(
|
case class SignRawTransactionOutputParameter(
|
||||||
txid: DoubleSha256DigestBE,
|
txid: DoubleSha256DigestBE,
|
||||||
@ -84,10 +86,11 @@ object RpcOpts {
|
|||||||
scriptPubKey: ScriptPubKey,
|
scriptPubKey: ScriptPubKey,
|
||||||
redeemScript: Option[ScriptPubKey] = None,
|
redeemScript: Option[ScriptPubKey] = None,
|
||||||
witnessScript: Option[WitnessScriptPubKey] = None,
|
witnessScript: Option[WitnessScriptPubKey] = None,
|
||||||
amount: Option[Bitcoins] = None)
|
amount: Option[Bitcoins] = None
|
||||||
|
)
|
||||||
|
|
||||||
implicit val signRawTransactionOutputParameterWrites: Writes[
|
implicit val signRawTransactionOutputParameterWrites
|
||||||
SignRawTransactionOutputParameter] =
|
: Writes[SignRawTransactionOutputParameter] =
|
||||||
Json.writes[SignRawTransactionOutputParameter]
|
Json.writes[SignRawTransactionOutputParameter]
|
||||||
|
|
||||||
object SignRawTransactionOutputParameter {
|
object SignRawTransactionOutputParameter {
|
||||||
@ -97,7 +100,8 @@ object RpcOpts {
|
|||||||
scriptPubKey: ScriptPubKey,
|
scriptPubKey: ScriptPubKey,
|
||||||
redeemScript: Option[ScriptPubKey] = None,
|
redeemScript: Option[ScriptPubKey] = None,
|
||||||
witnessScript: Option[WitnessScriptPubKey] = None,
|
witnessScript: Option[WitnessScriptPubKey] = None,
|
||||||
amount: Option[Bitcoins] = None): SignRawTransactionOutputParameter = {
|
amount: Option[Bitcoins] = None
|
||||||
|
): SignRawTransactionOutputParameter = {
|
||||||
SignRawTransactionOutputParameter(
|
SignRawTransactionOutputParameter(
|
||||||
txid = transactionInput.previousOutput.txIdBE,
|
txid = transactionInput.previousOutput.txIdBE,
|
||||||
vout = transactionInput.previousOutput.vout.toInt,
|
vout = transactionInput.previousOutput.vout.toInt,
|
||||||
@ -117,7 +121,8 @@ object RpcOpts {
|
|||||||
keys: Option[Vector[ECPrivateKeyBytes]] = None,
|
keys: Option[Vector[ECPrivateKeyBytes]] = None,
|
||||||
internal: Option[Boolean] = None,
|
internal: Option[Boolean] = None,
|
||||||
watchonly: Option[Boolean] = None,
|
watchonly: Option[Boolean] = None,
|
||||||
label: Option[String] = None)
|
label: Option[String] = None
|
||||||
|
)
|
||||||
|
|
||||||
case class ImportMultiAddress(address: BitcoinAddress)
|
case class ImportMultiAddress(address: BitcoinAddress)
|
||||||
|
|
||||||
@ -140,7 +145,8 @@ object RpcOpts {
|
|||||||
object LockUnspentOutputParameter {
|
object LockUnspentOutputParameter {
|
||||||
|
|
||||||
def fromOutPoint(
|
def fromOutPoint(
|
||||||
outPoint: TransactionOutPoint): LockUnspentOutputParameter = {
|
outPoint: TransactionOutPoint
|
||||||
|
): LockUnspentOutputParameter = {
|
||||||
LockUnspentOutputParameter(outPoint.txIdBE, outPoint.vout.toInt)
|
LockUnspentOutputParameter(outPoint.txIdBE, outPoint.vout.toInt)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +222,9 @@ object RpcOpts {
|
|||||||
override def fromString(string: String): AddressType = {
|
override def fromString(string: String): AddressType = {
|
||||||
fromStringOpt(string).getOrElse(
|
fromStringOpt(string).getOrElse(
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
s"Could not find AddressType for string: $string"))
|
s"Could not find AddressType for string: $string"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,7 +244,8 @@ object RpcOpts {
|
|||||||
case class BlockTemplateRequest(
|
case class BlockTemplateRequest(
|
||||||
mode: String,
|
mode: String,
|
||||||
capabilities: Vector[String],
|
capabilities: Vector[String],
|
||||||
rules: Vector[String])
|
rules: Vector[String]
|
||||||
|
)
|
||||||
|
|
||||||
implicit val blockTemplateRequest: Writes[BlockTemplateRequest] =
|
implicit val blockTemplateRequest: Writes[BlockTemplateRequest] =
|
||||||
Json.writes[BlockTemplateRequest]
|
Json.writes[BlockTemplateRequest]
|
||||||
|
@ -35,8 +35,8 @@ final case class DecodePsbtResultV22(
|
|||||||
unknown: Map[String, String],
|
unknown: Map[String, String],
|
||||||
inputs: Vector[RpcPsbtInputV22],
|
inputs: Vector[RpcPsbtInputV22],
|
||||||
outputs: Vector[RpcPsbtOutput],
|
outputs: Vector[RpcPsbtOutput],
|
||||||
fee: Option[Bitcoins])
|
fee: Option[Bitcoins]
|
||||||
extends DecodePsbtResult
|
) extends DecodePsbtResult
|
||||||
|
|
||||||
sealed abstract class RpcPsbtInput extends RpcPsbtResult {
|
sealed abstract class RpcPsbtInput extends RpcPsbtResult {
|
||||||
def nonWitnessUtxo: Option[RpcTransaction]
|
def nonWitnessUtxo: Option[RpcTransaction]
|
||||||
|
@ -30,15 +30,16 @@ case class MultiSigResultPostV20(
|
|||||||
address: BitcoinAddress,
|
address: BitcoinAddress,
|
||||||
redeemScript: ScriptPubKey,
|
redeemScript: ScriptPubKey,
|
||||||
descriptor: String,
|
descriptor: String,
|
||||||
warnings: Option[String]) //available in v23
|
warnings: Option[String]
|
||||||
|
) //available in v23
|
||||||
extends MultiSigResult
|
extends MultiSigResult
|
||||||
|
|
||||||
case class BumpFeeResult(
|
case class BumpFeeResult(
|
||||||
txid: DoubleSha256DigestBE,
|
txid: DoubleSha256DigestBE,
|
||||||
origfee: Bitcoins,
|
origfee: Bitcoins,
|
||||||
fee: Bitcoins, // TODO: Should be BitcoinFeeUnit
|
fee: Bitcoins, // TODO: Should be BitcoinFeeUnit
|
||||||
errors: Vector[String])
|
errors: Vector[String]
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
|
||||||
case class GetTransactionResult(
|
case class GetTransactionResult(
|
||||||
amount: Bitcoins,
|
amount: Bitcoins,
|
||||||
@ -56,14 +57,14 @@ case class GetTransactionResult(
|
|||||||
comment: Option[String],
|
comment: Option[String],
|
||||||
to: Option[String],
|
to: Option[String],
|
||||||
details: Vector[TransactionDetails],
|
details: Vector[TransactionDetails],
|
||||||
hex: Transaction)
|
hex: Transaction
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
|
||||||
case class SetWalletFlagResult(
|
case class SetWalletFlagResult(
|
||||||
flag_name: String,
|
flag_name: String,
|
||||||
flag_state: Boolean,
|
flag_state: Boolean,
|
||||||
warnings: Option[String])
|
warnings: Option[String]
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
|
||||||
case class GetBalancesResult(mine: BalanceInfo, watchonly: Option[BalanceInfo])
|
case class GetBalancesResult(mine: BalanceInfo, watchonly: Option[BalanceInfo])
|
||||||
extends WalletResult
|
extends WalletResult
|
||||||
@ -71,7 +72,8 @@ case class GetBalancesResult(mine: BalanceInfo, watchonly: Option[BalanceInfo])
|
|||||||
case class BalanceInfo(
|
case class BalanceInfo(
|
||||||
trusted: Bitcoins,
|
trusted: Bitcoins,
|
||||||
untrusted_pending: Bitcoins,
|
untrusted_pending: Bitcoins,
|
||||||
immature: Bitcoins)
|
immature: Bitcoins
|
||||||
|
)
|
||||||
|
|
||||||
case class TransactionDetails(
|
case class TransactionDetails(
|
||||||
involvesWatchonly: Option[Boolean],
|
involvesWatchonly: Option[Boolean],
|
||||||
@ -81,8 +83,8 @@ case class TransactionDetails(
|
|||||||
amount: Bitcoins,
|
amount: Bitcoins,
|
||||||
vout: Int,
|
vout: Int,
|
||||||
fee: Option[Bitcoins],
|
fee: Option[Bitcoins],
|
||||||
abandoned: Option[Boolean])
|
abandoned: Option[Boolean]
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
|
||||||
sealed trait GetWalletInfoResult extends WalletResult {
|
sealed trait GetWalletInfoResult extends WalletResult {
|
||||||
def walletname: String
|
def walletname: String
|
||||||
@ -114,8 +116,8 @@ case class GetWalletInfoResultPostV22(
|
|||||||
hdmasterkeyid: Option[Sha256Hash160Digest],
|
hdmasterkeyid: Option[Sha256Hash160Digest],
|
||||||
unlocked_until: Option[Int],
|
unlocked_until: Option[Int],
|
||||||
private_keys_enabled: Boolean,
|
private_keys_enabled: Boolean,
|
||||||
descriptors: Boolean)
|
descriptors: Boolean
|
||||||
extends GetWalletInfoResult
|
) extends GetWalletInfoResult
|
||||||
|
|
||||||
case class ImportMultiResult(success: Boolean, error: Option[ImportMultiError])
|
case class ImportMultiResult(success: Boolean, error: Option[ImportMultiError])
|
||||||
extends WalletResult
|
extends WalletResult
|
||||||
@ -125,15 +127,15 @@ case class ImportMultiError(code: Int, message: String) extends WalletResult
|
|||||||
case class RpcAddress(
|
case class RpcAddress(
|
||||||
address: BitcoinAddress,
|
address: BitcoinAddress,
|
||||||
balance: Bitcoins,
|
balance: Bitcoins,
|
||||||
account: Option[String])
|
account: Option[String]
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
|
||||||
case class RpcAccount(
|
case class RpcAccount(
|
||||||
involvesWatchonly: Boolean,
|
involvesWatchonly: Boolean,
|
||||||
account: String,
|
account: String,
|
||||||
amount: Bitcoins,
|
amount: Bitcoins,
|
||||||
confirmations: Int)
|
confirmations: Int
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
case class LoadWalletResult(name: String, warning: String) extends WalletResult
|
case class LoadWalletResult(name: String, warning: String) extends WalletResult
|
||||||
|
|
||||||
case class RescanBlockChainResult(start_height: Int, stop_height: Int)
|
case class RescanBlockChainResult(start_height: Int, stop_height: Int)
|
||||||
@ -146,28 +148,28 @@ case class ReceivedAddress(
|
|||||||
amount: Bitcoins,
|
amount: Bitcoins,
|
||||||
confirmations: Int,
|
confirmations: Int,
|
||||||
label: String,
|
label: String,
|
||||||
txids: Vector[DoubleSha256DigestBE])
|
txids: Vector[DoubleSha256DigestBE]
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
|
||||||
case class ReceivedAccount(
|
case class ReceivedAccount(
|
||||||
involvesWatchonly: Option[Boolean],
|
involvesWatchonly: Option[Boolean],
|
||||||
account: String,
|
account: String,
|
||||||
amount: Bitcoins,
|
amount: Bitcoins,
|
||||||
confirmations: Int,
|
confirmations: Int,
|
||||||
lable: Option[String])
|
lable: Option[String]
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
|
||||||
case class ReceivedLabel(
|
case class ReceivedLabel(
|
||||||
involvesWatchonly: Option[Boolean],
|
involvesWatchonly: Option[Boolean],
|
||||||
amount: Bitcoins,
|
amount: Bitcoins,
|
||||||
confirmations: Int,
|
confirmations: Int,
|
||||||
label: String)
|
label: String
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
|
||||||
case class ListSinceBlockResult(
|
case class ListSinceBlockResult(
|
||||||
transactions: Vector[Payment],
|
transactions: Vector[Payment],
|
||||||
lastblock: DoubleSha256DigestBE)
|
lastblock: DoubleSha256DigestBE
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
|
||||||
case class Payment(
|
case class Payment(
|
||||||
involvesWatchonly: Option[Boolean],
|
involvesWatchonly: Option[Boolean],
|
||||||
@ -188,8 +190,8 @@ case class Payment(
|
|||||||
timereceived: UInt32,
|
timereceived: UInt32,
|
||||||
bip125_replaceable: String,
|
bip125_replaceable: String,
|
||||||
comment: Option[String],
|
comment: Option[String],
|
||||||
to: Option[String])
|
to: Option[String]
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
|
||||||
case class ListTransactionsResult(
|
case class ListTransactionsResult(
|
||||||
account: Option[String],
|
account: Option[String],
|
||||||
@ -214,8 +216,8 @@ case class ListTransactionsResult(
|
|||||||
to: Option[String],
|
to: Option[String],
|
||||||
otheraccount: Option[String],
|
otheraccount: Option[String],
|
||||||
bip125_replaceable: String,
|
bip125_replaceable: String,
|
||||||
abandoned: Option[Boolean])
|
abandoned: Option[Boolean]
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
|
||||||
case class UnspentOutput(
|
case class UnspentOutput(
|
||||||
txid: DoubleSha256DigestBE,
|
txid: DoubleSha256DigestBE,
|
||||||
@ -228,8 +230,8 @@ case class UnspentOutput(
|
|||||||
confirmations: Int,
|
confirmations: Int,
|
||||||
spendable: Boolean,
|
spendable: Boolean,
|
||||||
solvable: Boolean,
|
solvable: Boolean,
|
||||||
reused: Option[Boolean])
|
reused: Option[Boolean]
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
|
||||||
sealed trait AddressInfoResult extends WalletResult {
|
sealed trait AddressInfoResult extends WalletResult {
|
||||||
def address: BitcoinAddress
|
def address: BitcoinAddress
|
||||||
@ -274,8 +276,8 @@ case class AddressInfoResultPreV18(
|
|||||||
hdkeypath: Option[BIP32Path],
|
hdkeypath: Option[BIP32Path],
|
||||||
hdseedid: Option[RipeMd160Digest],
|
hdseedid: Option[RipeMd160Digest],
|
||||||
hdmasterkeyid: Option[RipeMd160Digest],
|
hdmasterkeyid: Option[RipeMd160Digest],
|
||||||
labels: Vector[LabelResult])
|
labels: Vector[LabelResult]
|
||||||
extends AddressInfoResult
|
) extends AddressInfoResult
|
||||||
|
|
||||||
// The split into two case classes is to deal with the 22 param limit for case classes
|
// The split into two case classes is to deal with the 22 param limit for case classes
|
||||||
case class AddressInfoResultPostV18(
|
case class AddressInfoResultPostV18(
|
||||||
@ -297,8 +299,8 @@ case class AddressInfoResultPostV18(
|
|||||||
hdkeypath: Option[BIP32Path],
|
hdkeypath: Option[BIP32Path],
|
||||||
hdseedid: Option[RipeMd160Digest],
|
hdseedid: Option[RipeMd160Digest],
|
||||||
hdmasterfingerprint: Option[String],
|
hdmasterfingerprint: Option[String],
|
||||||
labels: Vector[LabelResult])
|
labels: Vector[LabelResult]
|
||||||
extends AddressInfoResult {
|
) extends AddressInfoResult {
|
||||||
override def ismine: Boolean = isProps.ismine
|
override def ismine: Boolean = isProps.ismine
|
||||||
def solvable: Boolean = isProps.solvable
|
def solvable: Boolean = isProps.solvable
|
||||||
override def iswatchonly: Boolean = isProps.iswatchonly
|
override def iswatchonly: Boolean = isProps.iswatchonly
|
||||||
@ -315,7 +317,8 @@ object AddressInfoResultPostV18 {
|
|||||||
iswatchonly: Boolean,
|
iswatchonly: Boolean,
|
||||||
isscript: Boolean,
|
isscript: Boolean,
|
||||||
iswitness: Boolean,
|
iswitness: Boolean,
|
||||||
iscompressed: Option[Boolean])
|
iscompressed: Option[Boolean]
|
||||||
|
)
|
||||||
|
|
||||||
case class AddressInfoResultPostV18WithoutIsProps(
|
case class AddressInfoResultPostV18WithoutIsProps(
|
||||||
address: BitcoinAddress,
|
address: BitcoinAddress,
|
||||||
@ -335,11 +338,13 @@ object AddressInfoResultPostV18 {
|
|||||||
hdkeypath: Option[BIP32Path],
|
hdkeypath: Option[BIP32Path],
|
||||||
hdseedid: Option[RipeMd160Digest],
|
hdseedid: Option[RipeMd160Digest],
|
||||||
hdmasterfingerprint: Option[String],
|
hdmasterfingerprint: Option[String],
|
||||||
labels: Vector[LabelResult])
|
labels: Vector[LabelResult]
|
||||||
|
)
|
||||||
|
|
||||||
def apply(
|
def apply(
|
||||||
info: AddressInfoResultPostV18WithoutIsProps,
|
info: AddressInfoResultPostV18WithoutIsProps,
|
||||||
isProps: AddressInfoIsProps): AddressInfoResultPostV18 = {
|
isProps: AddressInfoIsProps
|
||||||
|
): AddressInfoResultPostV18 = {
|
||||||
AddressInfoResultPostV18(
|
AddressInfoResultPostV18(
|
||||||
address = info.address,
|
address = info.address,
|
||||||
scriptPubKey = info.scriptPubKey,
|
scriptPubKey = info.scriptPubKey,
|
||||||
@ -401,7 +406,8 @@ object AddressInfoResultPostV21 {
|
|||||||
iswatchonly: Boolean,
|
iswatchonly: Boolean,
|
||||||
isscript: Boolean,
|
isscript: Boolean,
|
||||||
iswitness: Boolean,
|
iswitness: Boolean,
|
||||||
iscompressed: Option[Boolean])
|
iscompressed: Option[Boolean]
|
||||||
|
)
|
||||||
|
|
||||||
case class AddressInfoResultPostV21WithoutIsProps(
|
case class AddressInfoResultPostV21WithoutIsProps(
|
||||||
address: BitcoinAddress,
|
address: BitcoinAddress,
|
||||||
@ -420,11 +426,13 @@ object AddressInfoResultPostV21 {
|
|||||||
hdkeypath: Option[BIP32Path],
|
hdkeypath: Option[BIP32Path],
|
||||||
hdseedid: Option[RipeMd160Digest],
|
hdseedid: Option[RipeMd160Digest],
|
||||||
hdmasterfingerprint: Option[String],
|
hdmasterfingerprint: Option[String],
|
||||||
labels: Vector[String])
|
labels: Vector[String]
|
||||||
|
)
|
||||||
|
|
||||||
def apply(
|
def apply(
|
||||||
info: AddressInfoResultPostV21WithoutIsProps,
|
info: AddressInfoResultPostV21WithoutIsProps,
|
||||||
isProps: AddressInfoIsProps): AddressInfoResultPostV21 = {
|
isProps: AddressInfoIsProps
|
||||||
|
): AddressInfoResultPostV21 = {
|
||||||
AddressInfoResultPostV21(
|
AddressInfoResultPostV21(
|
||||||
address = info.address,
|
address = info.address,
|
||||||
scriptPubKey = info.scriptPubKey,
|
scriptPubKey = info.scriptPubKey,
|
||||||
@ -474,8 +482,8 @@ case class EmbeddedResult(
|
|||||||
witness_program: Option[String],
|
witness_program: Option[String],
|
||||||
pubkey: ECPublicKey,
|
pubkey: ECPublicKey,
|
||||||
address: BitcoinAddress,
|
address: BitcoinAddress,
|
||||||
scriptPubKey: ScriptPubKey)
|
scriptPubKey: ScriptPubKey
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
|
||||||
case class LabelResult(name: String, purpose: LabelPurpose) extends WalletResult
|
case class LabelResult(name: String, purpose: LabelPurpose) extends WalletResult
|
||||||
|
|
||||||
@ -494,5 +502,5 @@ final case class CreateWalletResult(
|
|||||||
|
|
||||||
case class ImportDescriptorResult(
|
case class ImportDescriptorResult(
|
||||||
success: Boolean,
|
success: Boolean,
|
||||||
warnings: Option[Vector[String]])
|
warnings: Option[Vector[String]]
|
||||||
extends WalletResult
|
) extends WalletResult
|
||||||
|
@ -18,34 +18,40 @@ object ContractDescriptorParser {
|
|||||||
|
|
||||||
def parseCmdLine(
|
def parseCmdLine(
|
||||||
value: ujson.Value,
|
value: ujson.Value,
|
||||||
announcementTLV: OracleAnnouncementTLV): ContractDescriptorTLV = {
|
announcementTLV: OracleAnnouncementTLV
|
||||||
|
): ContractDescriptorTLV = {
|
||||||
value match {
|
value match {
|
||||||
case obj: Obj =>
|
case obj: Obj =>
|
||||||
upickle.default
|
upickle.default
|
||||||
.read[ContractDescriptorV0TLV](obj)(Picklers.contractDescriptorV0)
|
.read[ContractDescriptorV0TLV](obj)(Picklers.contractDescriptorV0)
|
||||||
case arr: Arr =>
|
case arr: Arr =>
|
||||||
//we read the number of digits from the announcement,
|
// we read the number of digits from the announcement,
|
||||||
//take in tlv points for the payout curve
|
// take in tlv points for the payout curve
|
||||||
//and don't provide access to give a rounding mode as a parameter
|
// and don't provide access to give a rounding mode as a parameter
|
||||||
val payoutPoints: Vector[TLVPoint] = arr.value.toVector.map { pointJs =>
|
val payoutPoints: Vector[TLVPoint] = arr.value.toVector.map { pointJs =>
|
||||||
upickle.default
|
upickle.default
|
||||||
.read[TLVPoint](pointJs)(Picklers.tlvPointReader)
|
.read[TLVPoint](pointJs)(Picklers.tlvPointReader)
|
||||||
}
|
}
|
||||||
|
|
||||||
val payoutCurve = DLCPayoutCurve
|
val payoutCurve = DLCPayoutCurve
|
||||||
.fromPoints(payoutPoints,
|
.fromPoints(
|
||||||
serializationVersion = DLCSerializationVersion.Beta)
|
payoutPoints,
|
||||||
|
serializationVersion = DLCSerializationVersion.Beta
|
||||||
|
)
|
||||||
.toTLV
|
.toTLV
|
||||||
val numDigits = announcementTLV.eventTLV.eventDescriptor
|
val numDigits = announcementTLV.eventTLV.eventDescriptor
|
||||||
.asInstanceOf[DigitDecompositionEventDescriptorV0TLV]
|
.asInstanceOf[DigitDecompositionEventDescriptorV0TLV]
|
||||||
.numDigits
|
.numDigits
|
||||||
.toInt
|
.toInt
|
||||||
ContractDescriptorV1TLV(numDigits,
|
ContractDescriptorV1TLV(
|
||||||
payoutCurve,
|
numDigits,
|
||||||
RoundingIntervalsV0TLV.noRounding)
|
payoutCurve,
|
||||||
|
RoundingIntervalsV0TLV.noRounding
|
||||||
|
)
|
||||||
case fail @ (_: Num | _: Bool | Null | _: Str) =>
|
case fail @ (_: Num | _: Bool | Null | _: Str) =>
|
||||||
sys.error(
|
sys.error(
|
||||||
s"Cannot parse contract descriptor from $fail, expected json object or array")
|
s"Cannot parse contract descriptor from $fail, expected json object or array"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,8 +94,8 @@ object CLightningJsonModels {
|
|||||||
|
|
||||||
case class ListFundsResult(
|
case class ListFundsResult(
|
||||||
outputs: Vector[Output],
|
outputs: Vector[Output],
|
||||||
channels: Vector[ChannelFunds])
|
channels: Vector[ChannelFunds]
|
||||||
extends CLightningJsonModel
|
) extends CLightningJsonModel
|
||||||
|
|
||||||
case class Channel(
|
case class Channel(
|
||||||
source: NodeId,
|
source: NodeId,
|
||||||
@ -159,8 +159,8 @@ object CLightningJsonModels {
|
|||||||
connected: Boolean,
|
connected: Boolean,
|
||||||
features: ByteVector,
|
features: ByteVector,
|
||||||
netaddr: Vector[String],
|
netaddr: Vector[String],
|
||||||
channels: Vector[CLightningPeerChannel])
|
channels: Vector[CLightningPeerChannel]
|
||||||
extends CLightningJsonModel
|
) extends CLightningJsonModel
|
||||||
|
|
||||||
case class CLightningPeers(peers: Vector[CLightningPeer])
|
case class CLightningPeers(peers: Vector[CLightningPeer])
|
||||||
extends CLightningJsonModel
|
extends CLightningJsonModel
|
||||||
@ -228,8 +228,8 @@ object CLightningJsonModels {
|
|||||||
) extends CLightningJsonModel
|
) extends CLightningJsonModel
|
||||||
|
|
||||||
case class CLightningListInvoicesResult(
|
case class CLightningListInvoicesResult(
|
||||||
invoices: Vector[CLightningLookupInvoiceResult])
|
invoices: Vector[CLightningLookupInvoiceResult]
|
||||||
extends CLightningJsonModel
|
) extends CLightningJsonModel
|
||||||
|
|
||||||
case class CLightningPsbtResult(signed_psbt: PSBT) extends CLightningJsonModel
|
case class CLightningPsbtResult(signed_psbt: PSBT) extends CLightningJsonModel
|
||||||
|
|
||||||
|
@ -33,22 +33,27 @@ case class GetInfoResult(
|
|||||||
network: BitcoinNetwork,
|
network: BitcoinNetwork,
|
||||||
blockHeight: Long,
|
blockHeight: Long,
|
||||||
publicAddresses: Seq[InetSocketAddress],
|
publicAddresses: Seq[InetSocketAddress],
|
||||||
instanceId: UUID)
|
instanceId: UUID
|
||||||
|
)
|
||||||
|
|
||||||
case class PeerInfo(
|
case class PeerInfo(
|
||||||
nodeId: NodeId,
|
nodeId: NodeId,
|
||||||
state: PeerState,
|
state: PeerState,
|
||||||
address: Option[String],
|
address: Option[String],
|
||||||
channels: Int)
|
channels: Int
|
||||||
|
)
|
||||||
|
|
||||||
case class ChannelCommandResult(
|
case class ChannelCommandResult(
|
||||||
results: scala.collection.Map[
|
results: scala.collection.Map[Either[
|
||||||
Either[ShortChannelId, FundedChannelId],
|
ShortChannelId,
|
||||||
State]
|
FundedChannelId
|
||||||
|
],
|
||||||
|
State]
|
||||||
)
|
)
|
||||||
|
|
||||||
case class UpdateRelayFeeResult(
|
case class UpdateRelayFeeResult(
|
||||||
results: Map[Either[ShortChannelId, FundedChannelId], UpdateRelayFee])
|
results: Map[Either[ShortChannelId, FundedChannelId], UpdateRelayFee]
|
||||||
|
)
|
||||||
|
|
||||||
sealed trait UpdateRelayFee
|
sealed trait UpdateRelayFee
|
||||||
|
|
||||||
@ -57,8 +62,8 @@ object UpdateRelayFee {
|
|||||||
case class OK(
|
case class OK(
|
||||||
channelId: ChannelId,
|
channelId: ChannelId,
|
||||||
feeBaseMsat: MilliSatoshis,
|
feeBaseMsat: MilliSatoshis,
|
||||||
feeProportionalMillionths: Long)
|
feeProportionalMillionths: Long
|
||||||
extends UpdateRelayFee
|
) extends UpdateRelayFee
|
||||||
|
|
||||||
case class Error(message: String) extends UpdateRelayFee
|
case class Error(message: String) extends UpdateRelayFee
|
||||||
}
|
}
|
||||||
@ -84,12 +89,10 @@ object ChannelCommandResult extends StringFactory[State] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This is the data model returned by the RPC call
|
/** This is the data model returned by the RPC call `channels nodeId`. The
|
||||||
* `channels nodeId`. The content of the objects
|
* content of the objects being returne differ based on whatever state the
|
||||||
* being returne differ based on whatever state
|
* channel is in. The member of this abstract class are in eveyr channel state,
|
||||||
* the channel is in. The member of this abstract
|
* whereas other channel states may have extra information.
|
||||||
* class are in eveyr channel state, whereas other
|
|
||||||
* channel states may have extra information.
|
|
||||||
*/
|
*/
|
||||||
sealed abstract class ChannelInfo {
|
sealed abstract class ChannelInfo {
|
||||||
def nodeId: NodeId
|
def nodeId: NodeId
|
||||||
@ -111,8 +114,8 @@ case class BaseChannelInfo(
|
|||||||
state: ChannelState
|
state: ChannelState
|
||||||
) extends ChannelInfo
|
) extends ChannelInfo
|
||||||
|
|
||||||
/** This represents the case where the channel is
|
/** This represents the case where the channel is in state `NORMAL` (i.e. an
|
||||||
* in state `NORMAL` (i.e. an open channel)
|
* open channel)
|
||||||
*/
|
*/
|
||||||
case class OpenChannelInfo(
|
case class OpenChannelInfo(
|
||||||
nodeId: NodeId,
|
nodeId: NodeId,
|
||||||
@ -129,7 +132,8 @@ case class UnknownFeature(bitIndex: Int)
|
|||||||
|
|
||||||
case class Features(
|
case class Features(
|
||||||
activated: Set[ActivatedFeature],
|
activated: Set[ActivatedFeature],
|
||||||
unknown: Set[UnknownFeature])
|
unknown: Set[UnknownFeature]
|
||||||
|
)
|
||||||
|
|
||||||
case class NodeInfo(
|
case class NodeInfo(
|
||||||
signature: ECDigitalSignature,
|
signature: ECDigitalSignature,
|
||||||
@ -138,7 +142,8 @@ case class NodeInfo(
|
|||||||
nodeId: NodeId,
|
nodeId: NodeId,
|
||||||
rgbColor: String,
|
rgbColor: String,
|
||||||
alias: String,
|
alias: String,
|
||||||
addresses: Vector[InetSocketAddress])
|
addresses: Vector[InetSocketAddress]
|
||||||
|
)
|
||||||
|
|
||||||
case class ChannelDesc(shortChannelId: ShortChannelId, a: NodeId, b: NodeId)
|
case class ChannelDesc(shortChannelId: ShortChannelId, a: NodeId, b: NodeId)
|
||||||
|
|
||||||
@ -154,7 +159,7 @@ case class NetworkFeesResult(
|
|||||||
txId: DoubleSha256DigestBE,
|
txId: DoubleSha256DigestBE,
|
||||||
fee: Satoshis,
|
fee: Satoshis,
|
||||||
txType: String,
|
txType: String,
|
||||||
timestamp: Instant //milliseconds
|
timestamp: Instant // milliseconds
|
||||||
)
|
)
|
||||||
|
|
||||||
case class ChannelStats(
|
case class ChannelStats(
|
||||||
@ -189,7 +194,8 @@ case class RealChannelId(status: String, realScid: ShortChannelId)
|
|||||||
case class ShortIds(
|
case class ShortIds(
|
||||||
real: RealChannelId,
|
real: RealChannelId,
|
||||||
localAlias: String,
|
localAlias: String,
|
||||||
remoteAlias: String)
|
remoteAlias: String
|
||||||
|
)
|
||||||
|
|
||||||
case class UsableBalancesResult(
|
case class UsableBalancesResult(
|
||||||
remoteNodeId: NodeId,
|
remoteNodeId: NodeId,
|
||||||
@ -210,7 +216,7 @@ object ReceivedPayment {
|
|||||||
case class Part(
|
case class Part(
|
||||||
amount: MilliSatoshis,
|
amount: MilliSatoshis,
|
||||||
fromChannelId: FundedChannelId,
|
fromChannelId: FundedChannelId,
|
||||||
timestamp: Instant //milliseconds
|
timestamp: Instant // milliseconds
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +226,7 @@ case class RelayedPayment(
|
|||||||
paymentHash: Sha256Digest,
|
paymentHash: Sha256Digest,
|
||||||
fromChannelId: FundedChannelId,
|
fromChannelId: FundedChannelId,
|
||||||
toChannelId: FundedChannelId,
|
toChannelId: FundedChannelId,
|
||||||
timestamp: Instant //milliseconds
|
timestamp: Instant // milliseconds
|
||||||
)
|
)
|
||||||
|
|
||||||
case class SentPayment(
|
case class SentPayment(
|
||||||
@ -239,7 +245,7 @@ object SentPayment {
|
|||||||
amount: MilliSatoshis,
|
amount: MilliSatoshis,
|
||||||
feesPaid: MilliSatoshis,
|
feesPaid: MilliSatoshis,
|
||||||
toChannelId: FundedChannelId,
|
toChannelId: FundedChannelId,
|
||||||
timestamp: Instant //milliseconds
|
timestamp: Instant // milliseconds
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,13 +255,14 @@ case class ChannelUpdate(
|
|||||||
signature: ECDigitalSignature,
|
signature: ECDigitalSignature,
|
||||||
chainHash: DoubleSha256Digest,
|
chainHash: DoubleSha256Digest,
|
||||||
shortChannelId: ShortChannelId,
|
shortChannelId: ShortChannelId,
|
||||||
timestamp: Instant, //seconds
|
timestamp: Instant, // seconds
|
||||||
channelFlags: ChannelFlags,
|
channelFlags: ChannelFlags,
|
||||||
cltvExpiryDelta: Int,
|
cltvExpiryDelta: Int,
|
||||||
htlcMinimumMsat: MilliSatoshis,
|
htlcMinimumMsat: MilliSatoshis,
|
||||||
feeProportionalMillionths: FeeProportionalMillionths,
|
feeProportionalMillionths: FeeProportionalMillionths,
|
||||||
htlcMaximumMsat: Option[MilliSatoshis],
|
htlcMaximumMsat: Option[MilliSatoshis],
|
||||||
feeBaseMsat: MilliSatoshis)
|
feeBaseMsat: MilliSatoshis
|
||||||
|
)
|
||||||
|
|
||||||
case class ChannelResult(
|
case class ChannelResult(
|
||||||
nodeId: NodeId,
|
nodeId: NodeId,
|
||||||
@ -263,7 +270,8 @@ case class ChannelResult(
|
|||||||
state: ChannelState,
|
state: ChannelState,
|
||||||
feeBaseMsat: Option[MilliSatoshis],
|
feeBaseMsat: Option[MilliSatoshis],
|
||||||
feeProportionalMillionths: Option[FeeProportionalMillionths],
|
feeProportionalMillionths: Option[FeeProportionalMillionths],
|
||||||
data: JsObject) {
|
data: JsObject
|
||||||
|
) {
|
||||||
|
|
||||||
lazy val shortChannelId: Option[ShortChannelId] =
|
lazy val shortChannelId: Option[ShortChannelId] =
|
||||||
(data \ "shortIds" \ "real" \ "realScid").validate[ShortChannelId].asOpt
|
(data \ "shortIds" \ "real" \ "realScid").validate[ShortChannelId].asOpt
|
||||||
@ -273,12 +281,13 @@ case class ChannelResult(
|
|||||||
|
|
||||||
case class InvoiceResult(
|
case class InvoiceResult(
|
||||||
prefix: LnHumanReadablePart,
|
prefix: LnHumanReadablePart,
|
||||||
timestamp: Instant, //seconds
|
timestamp: Instant, // seconds
|
||||||
nodeId: NodeId,
|
nodeId: NodeId,
|
||||||
serialized: String,
|
serialized: String,
|
||||||
description: String,
|
description: String,
|
||||||
paymentHash: Sha256Digest,
|
paymentHash: Sha256Digest,
|
||||||
expiry: FiniteDuration)
|
expiry: FiniteDuration
|
||||||
|
)
|
||||||
|
|
||||||
case class PaymentId(value: UUID) {
|
case class PaymentId(value: UUID) {
|
||||||
override def toString: String = value.toString
|
override def toString: String = value.toString
|
||||||
@ -288,16 +297,17 @@ case class SendToRouteResult(paymentId: PaymentId, parentId: PaymentId)
|
|||||||
|
|
||||||
case class PaymentRequest(
|
case class PaymentRequest(
|
||||||
prefix: LnHumanReadablePart,
|
prefix: LnHumanReadablePart,
|
||||||
timestamp: Instant, //seconds
|
timestamp: Instant, // seconds
|
||||||
nodeId: NodeId,
|
nodeId: NodeId,
|
||||||
serialized: String,
|
serialized: String,
|
||||||
description: String,
|
description: String,
|
||||||
paymentHash: Sha256Digest,
|
paymentHash: Sha256Digest,
|
||||||
paymentMetadata: String,
|
paymentMetadata: String,
|
||||||
expiry: FiniteDuration, //seconds
|
expiry: FiniteDuration, // seconds
|
||||||
minFinalCltvExpiry: Int,
|
minFinalCltvExpiry: Int,
|
||||||
amount: Option[MilliSatoshis],
|
amount: Option[MilliSatoshis],
|
||||||
features: Features)
|
features: Features
|
||||||
|
)
|
||||||
|
|
||||||
sealed trait PaymentType
|
sealed trait PaymentType
|
||||||
|
|
||||||
@ -314,7 +324,7 @@ object PaymentType extends StringFactory[PaymentType] {
|
|||||||
case "SwapIn" => SwapIn
|
case "SwapIn" => SwapIn
|
||||||
case "SwapOut" => SwapOut
|
case "SwapOut" => SwapOut
|
||||||
case "placeholder" => Placeholder
|
case "placeholder" => Placeholder
|
||||||
case _ => throw new RuntimeException(s"Unknown payment type `$str`")
|
case _ => throw new RuntimeException(s"Unknown payment type `$str`")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -328,16 +338,18 @@ case class OutgoingPayment(
|
|||||||
amount: MilliSatoshis,
|
amount: MilliSatoshis,
|
||||||
recipientAmount: MilliSatoshis,
|
recipientAmount: MilliSatoshis,
|
||||||
recipientNodeId: NodeId,
|
recipientNodeId: NodeId,
|
||||||
createdAt: Instant, //milliseconds
|
createdAt: Instant, // milliseconds
|
||||||
paymentRequest: Option[PaymentRequest],
|
paymentRequest: Option[PaymentRequest],
|
||||||
status: OutgoingPaymentStatus)
|
status: OutgoingPaymentStatus
|
||||||
|
)
|
||||||
|
|
||||||
case class IncomingPayment(
|
case class IncomingPayment(
|
||||||
paymentRequest: PaymentRequest,
|
paymentRequest: PaymentRequest,
|
||||||
paymentPreimage: PaymentPreimage,
|
paymentPreimage: PaymentPreimage,
|
||||||
paymentType: PaymentType,
|
paymentType: PaymentType,
|
||||||
createdAt: Instant, //milliseconds
|
createdAt: Instant, // milliseconds
|
||||||
status: IncomingPaymentStatus)
|
status: IncomingPaymentStatus
|
||||||
|
)
|
||||||
|
|
||||||
sealed trait IncomingPaymentStatus
|
sealed trait IncomingPaymentStatus
|
||||||
|
|
||||||
@ -349,7 +361,7 @@ object IncomingPaymentStatus {
|
|||||||
|
|
||||||
case class Received(
|
case class Received(
|
||||||
amount: MilliSatoshis,
|
amount: MilliSatoshis,
|
||||||
receivedAt: Instant //milliseconds
|
receivedAt: Instant // milliseconds
|
||||||
) extends IncomingPaymentStatus
|
) extends IncomingPaymentStatus
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -363,7 +375,7 @@ object OutgoingPaymentStatus {
|
|||||||
paymentPreimage: PaymentPreimage,
|
paymentPreimage: PaymentPreimage,
|
||||||
feesPaid: MilliSatoshis,
|
feesPaid: MilliSatoshis,
|
||||||
route: Seq[Hop],
|
route: Seq[Hop],
|
||||||
completedAt: Instant //milliseconds
|
completedAt: Instant // milliseconds
|
||||||
) extends OutgoingPaymentStatus
|
) extends OutgoingPaymentStatus
|
||||||
|
|
||||||
case class Failed(failures: Seq[PaymentFailure], completedAt: Instant)
|
case class Failed(failures: Seq[PaymentFailure], completedAt: Instant)
|
||||||
@ -373,7 +385,8 @@ object OutgoingPaymentStatus {
|
|||||||
case class PaymentFailure(
|
case class PaymentFailure(
|
||||||
failureType: PaymentFailure.Type,
|
failureType: PaymentFailure.Type,
|
||||||
failureMessage: String,
|
failureMessage: String,
|
||||||
failedRoute: Seq[Hop])
|
failedRoute: Seq[Hop]
|
||||||
|
)
|
||||||
|
|
||||||
object PaymentFailure {
|
object PaymentFailure {
|
||||||
sealed trait Type
|
sealed trait Type
|
||||||
@ -385,7 +398,8 @@ object PaymentFailure {
|
|||||||
case class Hop(
|
case class Hop(
|
||||||
nodeId: NodeId,
|
nodeId: NodeId,
|
||||||
nextNodeId: NodeId,
|
nextNodeId: NodeId,
|
||||||
shortChannelId: Option[ShortChannelId])
|
shortChannelId: Option[ShortChannelId]
|
||||||
|
)
|
||||||
|
|
||||||
sealed trait WebSocketEvent
|
sealed trait WebSocketEvent
|
||||||
|
|
||||||
@ -397,7 +411,7 @@ object WebSocketEvent {
|
|||||||
paymentHash: Sha256Digest,
|
paymentHash: Sha256Digest,
|
||||||
fromChannelId: FundedChannelId,
|
fromChannelId: FundedChannelId,
|
||||||
toChannelId: FundedChannelId,
|
toChannelId: FundedChannelId,
|
||||||
timestamp: Instant //milliseconds
|
timestamp: Instant // milliseconds
|
||||||
) extends WebSocketEvent
|
) extends WebSocketEvent
|
||||||
|
|
||||||
case class PaymentReceived(
|
case class PaymentReceived(
|
||||||
@ -442,7 +456,7 @@ object WebSocketEvent {
|
|||||||
case class PaymentSettlingOnchain(
|
case class PaymentSettlingOnchain(
|
||||||
amount: MilliSatoshis,
|
amount: MilliSatoshis,
|
||||||
paymentHash: Sha256Digest,
|
paymentHash: Sha256Digest,
|
||||||
timestamp: Instant //milliseconds
|
timestamp: Instant // milliseconds
|
||||||
) extends WebSocketEvent
|
) extends WebSocketEvent
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -456,4 +470,5 @@ case class WalletTransaction(
|
|||||||
blockHash: DoubleSha256DigestBE,
|
blockHash: DoubleSha256DigestBE,
|
||||||
confirmations: Long,
|
confirmations: Long,
|
||||||
txid: DoubleSha256DigestBE,
|
txid: DoubleSha256DigestBE,
|
||||||
timestamp: Long)
|
timestamp: Long
|
||||||
|
)
|
||||||
|
@ -16,8 +16,8 @@ case class AddInvoiceResult(
|
|||||||
rHash: PaymentHashTag,
|
rHash: PaymentHashTag,
|
||||||
invoice: LnInvoice,
|
invoice: LnInvoice,
|
||||||
addIndex: UInt64,
|
addIndex: UInt64,
|
||||||
paymentAddr: ByteVector)
|
paymentAddr: ByteVector
|
||||||
extends LndModel
|
) extends LndModel
|
||||||
|
|
||||||
case class UTXOResult(
|
case class UTXOResult(
|
||||||
address: BitcoinAddress,
|
address: BitcoinAddress,
|
||||||
|
@ -14,7 +14,9 @@ import ujson.Value
|
|||||||
|
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
|
|
||||||
/** The event type being sent over the websocket. An example is [[WalletWsType.NewAddress]] */
|
/** The event type being sent over the websocket. An example is
|
||||||
|
* [[WalletWsType.NewAddress]]
|
||||||
|
*/
|
||||||
sealed trait WsType
|
sealed trait WsType
|
||||||
|
|
||||||
object WsType extends StringFactory[WsType] {
|
object WsType extends StringFactory[WsType] {
|
||||||
@ -46,15 +48,17 @@ object WalletWsType extends StringFactory[WalletWsType] {
|
|||||||
case object FeeRateChange extends WalletWsType
|
case object FeeRateChange extends WalletWsType
|
||||||
|
|
||||||
private val all =
|
private val all =
|
||||||
Vector(TxProcessed,
|
Vector(
|
||||||
TxBroadcast,
|
TxProcessed,
|
||||||
ReservedUtxos,
|
TxBroadcast,
|
||||||
NewAddress,
|
ReservedUtxos,
|
||||||
DLCStateChange,
|
NewAddress,
|
||||||
DLCOfferAdd,
|
DLCStateChange,
|
||||||
DLCOfferRemove,
|
DLCOfferAdd,
|
||||||
RescanComplete,
|
DLCOfferRemove,
|
||||||
FeeRateChange)
|
RescanComplete,
|
||||||
|
FeeRateChange
|
||||||
|
)
|
||||||
|
|
||||||
override def fromStringOpt(string: String): Option[WalletWsType] = {
|
override def fromStringOpt(string: String): Option[WalletWsType] = {
|
||||||
all.find(_.toString.toLowerCase() == string.toLowerCase)
|
all.find(_.toString.toLowerCase() == string.toLowerCase)
|
||||||
@ -140,9 +144,9 @@ object DLCNodeWsType extends StringFactory[DLCNodeWsType] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A notification that we send over the websocket.
|
/** A notification that we send over the websocket. The type of the notification
|
||||||
* The type of the notification is indicated by [[WsType]].
|
* is indicated by [[WsType]]. An example is
|
||||||
* An example is [[org.bitcoins.commons.jsonmodels.ws.WalletNotification.NewAddressNotification]]
|
* [[org.bitcoins.commons.jsonmodels.ws.WalletNotification.NewAddressNotification]]
|
||||||
* This sends a notification that the wallet generated a new address
|
* This sends a notification that the wallet generated a new address
|
||||||
*/
|
*/
|
||||||
sealed trait WsNotification[T] {
|
sealed trait WsNotification[T] {
|
||||||
@ -263,13 +267,14 @@ object ChainNotification {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case class CompactFilterHeaderProcessedNotification(
|
case class CompactFilterHeaderProcessedNotification(
|
||||||
payload: CompactFilterHeaderDb)
|
payload: CompactFilterHeaderDb
|
||||||
extends ChainNotification[CompactFilterHeaderDb] {
|
) extends ChainNotification[CompactFilterHeaderDb] {
|
||||||
override val `type`: ChainWsType = ChainWsType.CompactFilterHeaderProcessed
|
override val `type`: ChainWsType = ChainWsType.CompactFilterHeaderProcessed
|
||||||
|
|
||||||
override val json: ujson.Value = {
|
override val json: ujson.Value = {
|
||||||
upickle.default.writeJs(this)(
|
upickle.default.writeJs(this)(
|
||||||
WsPicklers.compactFilterHeaderProcessedPickler)
|
WsPicklers.compactFilterHeaderProcessedPickler
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +316,8 @@ object DLCNodeNotification {
|
|||||||
override def `type`: DLCNodeWsType = DLCNodeWsType.DLCConnectionInitiated
|
override def `type`: DLCNodeWsType = DLCNodeWsType.DLCConnectionInitiated
|
||||||
|
|
||||||
override def json: Value = upickle.default.writeJs(this)(
|
override def json: Value = upickle.default.writeJs(this)(
|
||||||
WsPicklers.dlcNodeConnectionInitiatedPickler)
|
WsPicklers.dlcNodeConnectionInitiatedPickler
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class DLCNodeConnectionEstablished(payload: InetSocketAddress)
|
case class DLCNodeConnectionEstablished(payload: InetSocketAddress)
|
||||||
@ -319,7 +325,8 @@ object DLCNodeNotification {
|
|||||||
override def `type`: DLCNodeWsType = DLCNodeWsType.DLCConnectionEstablished
|
override def `type`: DLCNodeWsType = DLCNodeWsType.DLCConnectionEstablished
|
||||||
|
|
||||||
override def json: Value = upickle.default.writeJs(this)(
|
override def json: Value = upickle.default.writeJs(this)(
|
||||||
WsPicklers.dlcNodeConnectionEstablishedPickler)
|
WsPicklers.dlcNodeConnectionEstablishedPickler
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class DLCNodeConnectionFailed(payload: InetSocketAddress)
|
case class DLCNodeConnectionFailed(payload: InetSocketAddress)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -51,21 +51,21 @@ import scala.util.{Failure, Success, Try}
|
|||||||
|
|
||||||
object JsonReaders {
|
object JsonReaders {
|
||||||
|
|
||||||
/** Tries to prase the provided JSON into a map with keys of
|
/** Tries to prase the provided JSON into a map with keys of type `K` and
|
||||||
* type `K` and values of type `V`
|
* values of type `V`
|
||||||
*/
|
*/
|
||||||
def mapReads[K, V](js: JsValue)(implicit
|
def mapReads[K, V](
|
||||||
readsK: Reads[K],
|
js: JsValue
|
||||||
readsV: Reads[V]): JsResult[Map[K, V]] = {
|
)(implicit readsK: Reads[K], readsV: Reads[V]): JsResult[Map[K, V]] = {
|
||||||
js.validate[JsObject].flatMap { jsObj =>
|
js.validate[JsObject].flatMap { jsObj =>
|
||||||
val jsResults: scala.collection.Seq[(JsResult[K], JsResult[V])] =
|
val jsResults: scala.collection.Seq[(JsResult[K], JsResult[V])] =
|
||||||
jsObj.fields.map { case (key, value) =>
|
jsObj.fields.map { case (key, value) =>
|
||||||
JsString(key).validate[K] -> value.validate[V]
|
JsString(key).validate[K] -> value.validate[V]
|
||||||
}
|
}
|
||||||
|
|
||||||
val allErrors: scala.collection.Seq[(
|
val allErrors: scala.collection.Seq[
|
||||||
JsPath,
|
(JsPath, scala.collection.Seq[JsonValidationError])
|
||||||
scala.collection.Seq[JsonValidationError])] =
|
] =
|
||||||
jsResults.collect {
|
jsResults.collect {
|
||||||
case (JsError(keyErrors), _) => keyErrors
|
case (JsError(keyErrors), _) => keyErrors
|
||||||
case (_, JsError(valueErrors)) => valueErrors
|
case (_, JsError(valueErrors)) => valueErrors
|
||||||
@ -91,16 +91,20 @@ object JsonReaders {
|
|||||||
|
|
||||||
override def reads(json: JsValue): JsResult[ZonedDateTime] =
|
override def reads(json: JsValue): JsResult[ZonedDateTime] =
|
||||||
SerializerUtil.processJsNumberBigInt[ZonedDateTime](bigInt =>
|
SerializerUtil.processJsNumberBigInt[ZonedDateTime](bigInt =>
|
||||||
ZonedDateTime.ofInstant(Instant.ofEpochSecond(bigInt.toLong),
|
ZonedDateTime.ofInstant(
|
||||||
ZoneOffset.UTC))(json)
|
Instant.ofEpochSecond(bigInt.toLong),
|
||||||
|
ZoneOffset.UTC
|
||||||
|
))(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object LocalDateTimeReads extends Reads[LocalDateTime] {
|
implicit object LocalDateTimeReads extends Reads[LocalDateTime] {
|
||||||
|
|
||||||
override def reads(json: JsValue): JsResult[LocalDateTime] =
|
override def reads(json: JsValue): JsResult[LocalDateTime] =
|
||||||
SerializerUtil.processJsNumberBigInt[LocalDateTime](bigInt =>
|
SerializerUtil.processJsNumberBigInt[LocalDateTime](bigInt =>
|
||||||
LocalDateTime.ofInstant(Instant.ofEpochSecond(bigInt.toLong),
|
LocalDateTime.ofInstant(
|
||||||
ZoneId.systemDefault()))(json)
|
Instant.ofEpochSecond(bigInt.toLong),
|
||||||
|
ZoneId.systemDefault()
|
||||||
|
))(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object BigIntReads extends Reads[BigInt] {
|
implicit object BigIntReads extends Reads[BigInt] {
|
||||||
@ -119,21 +123,24 @@ object JsonReaders {
|
|||||||
|
|
||||||
override def reads(json: JsValue): JsResult[RipeMd160Digest] =
|
override def reads(json: JsValue): JsResult[RipeMd160Digest] =
|
||||||
SerializerUtil.processJsString[RipeMd160Digest](RipeMd160Digest.fromHex)(
|
SerializerUtil.processJsString[RipeMd160Digest](RipeMd160Digest.fromHex)(
|
||||||
json)
|
json
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object RipeMd160DigestBEReads extends Reads[RipeMd160DigestBE] {
|
implicit object RipeMd160DigestBEReads extends Reads[RipeMd160DigestBE] {
|
||||||
|
|
||||||
override def reads(json: JsValue): JsResult[RipeMd160DigestBE] =
|
override def reads(json: JsValue): JsResult[RipeMd160DigestBE] =
|
||||||
SerializerUtil.processJsString[RipeMd160DigestBE](
|
SerializerUtil.processJsString[RipeMd160DigestBE](
|
||||||
RipeMd160DigestBE.fromHex)(json)
|
RipeMd160DigestBE.fromHex
|
||||||
|
)(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object DoubleSha256DigestReads extends Reads[DoubleSha256Digest] {
|
implicit object DoubleSha256DigestReads extends Reads[DoubleSha256Digest] {
|
||||||
|
|
||||||
override def reads(json: JsValue): JsResult[DoubleSha256Digest] =
|
override def reads(json: JsValue): JsResult[DoubleSha256Digest] =
|
||||||
SerializerUtil.processJsString[DoubleSha256Digest](
|
SerializerUtil.processJsString[DoubleSha256Digest](
|
||||||
DoubleSha256Digest.fromHex)(json)
|
DoubleSha256Digest.fromHex
|
||||||
|
)(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object DoubleSha256DigestBEReads
|
implicit object DoubleSha256DigestBEReads
|
||||||
@ -141,7 +148,8 @@ object JsonReaders {
|
|||||||
|
|
||||||
override def reads(json: JsValue): JsResult[DoubleSha256DigestBE] =
|
override def reads(json: JsValue): JsResult[DoubleSha256DigestBE] =
|
||||||
SerializerUtil.processJsString[DoubleSha256DigestBE](
|
SerializerUtil.processJsString[DoubleSha256DigestBE](
|
||||||
DoubleSha256DigestBE.fromHex)(json)
|
DoubleSha256DigestBE.fromHex
|
||||||
|
)(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object BitcoinsReads extends Reads[Bitcoins] {
|
implicit object BitcoinsReads extends Reads[Bitcoins] {
|
||||||
@ -161,7 +169,8 @@ object JsonReaders {
|
|||||||
|
|
||||||
override def reads(json: JsValue): JsResult[Satoshis] =
|
override def reads(json: JsValue): JsResult[Satoshis] =
|
||||||
SerializerUtil.processJsNumber[Satoshis](num => Satoshis(num.toBigInt))(
|
SerializerUtil.processJsNumber[Satoshis](num => Satoshis(num.toBigInt))(
|
||||||
json)
|
json
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object BlockHeaderReads extends Reads[BlockHeader] {
|
implicit object BlockHeaderReads extends Reads[BlockHeader] {
|
||||||
@ -266,8 +275,10 @@ object JsonReaders {
|
|||||||
case JsNumber(num) if num != 0 =>
|
case JsNumber(num) if num != 0 =>
|
||||||
SerializerUtil.buildErrorMsg("Expected witness_version 0", num)
|
SerializerUtil.buildErrorMsg("Expected witness_version 0", num)
|
||||||
case err =>
|
case err =>
|
||||||
SerializerUtil.buildErrorMsg("Expected numerical witness_version",
|
SerializerUtil.buildErrorMsg(
|
||||||
err)
|
"Expected numerical witness_version",
|
||||||
|
err
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,21 +327,24 @@ object JsonReaders {
|
|||||||
|
|
||||||
override def reads(json: JsValue): JsResult[ScriptPubKey] =
|
override def reads(json: JsValue): JsResult[ScriptPubKey] =
|
||||||
SerializerUtil.processJsString[ScriptPubKey](ScriptPubKey.fromAsmHex)(
|
SerializerUtil.processJsString[ScriptPubKey](ScriptPubKey.fromAsmHex)(
|
||||||
json)
|
json
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object ScriptWitnessReads extends Reads[ScriptWitness] {
|
implicit object ScriptWitnessReads extends Reads[ScriptWitness] {
|
||||||
|
|
||||||
override def reads(json: JsValue): JsResult[ScriptWitness] =
|
override def reads(json: JsValue): JsResult[ScriptWitness] =
|
||||||
SerializerUtil.processJsStringOpt[ScriptWitness](
|
SerializerUtil.processJsStringOpt[ScriptWitness](
|
||||||
ScriptWitness.fromHexOpt)(json)
|
ScriptWitness.fromHexOpt
|
||||||
|
)(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object DescriptorReads extends Reads[Descriptor] {
|
implicit object DescriptorReads extends Reads[Descriptor] {
|
||||||
|
|
||||||
override def reads(json: JsValue): JsResult[Descriptor] = {
|
override def reads(json: JsValue): JsResult[Descriptor] = {
|
||||||
SerializerUtil.processJsStringOpt[Descriptor](Descriptor.fromStringOpt)(
|
SerializerUtil.processJsStringOpt[Descriptor](Descriptor.fromStringOpt)(
|
||||||
json)
|
json
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,7 +358,8 @@ object JsonReaders {
|
|||||||
|
|
||||||
override def reads(json: JsValue): JsResult[Sha256Hash160Digest] =
|
override def reads(json: JsValue): JsResult[Sha256Hash160Digest] =
|
||||||
SerializerUtil.processJsString[Sha256Hash160Digest](
|
SerializerUtil.processJsString[Sha256Hash160Digest](
|
||||||
Sha256Hash160Digest.fromHex)(json)
|
Sha256Hash160Digest.fromHex
|
||||||
|
)(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object ECPublicKeyReads extends Reads[ECPublicKey] {
|
implicit object ECPublicKeyReads extends Reads[ECPublicKey] {
|
||||||
@ -357,14 +372,16 @@ object JsonReaders {
|
|||||||
|
|
||||||
override def reads(json: JsValue): JsResult[ECPublicKeyBytes] =
|
override def reads(json: JsValue): JsResult[ECPublicKeyBytes] =
|
||||||
SerializerUtil.processJsString[ECPublicKeyBytes](
|
SerializerUtil.processJsString[ECPublicKeyBytes](
|
||||||
ECPublicKeyBytes.fromHex)(json)
|
ECPublicKeyBytes.fromHex
|
||||||
|
)(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object SchnorrPublicKeyReads extends Reads[SchnorrPublicKey] {
|
implicit object SchnorrPublicKeyReads extends Reads[SchnorrPublicKey] {
|
||||||
|
|
||||||
override def reads(json: JsValue): JsResult[SchnorrPublicKey] =
|
override def reads(json: JsValue): JsResult[SchnorrPublicKey] =
|
||||||
SerializerUtil.processJsString[SchnorrPublicKey](
|
SerializerUtil.processJsString[SchnorrPublicKey](
|
||||||
SchnorrPublicKey.fromHex)(json)
|
SchnorrPublicKey.fromHex
|
||||||
|
)(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object SchnorrNonceReads extends Reads[SchnorrNonce] {
|
implicit object SchnorrNonceReads extends Reads[SchnorrNonce] {
|
||||||
@ -378,7 +395,8 @@ object JsonReaders {
|
|||||||
|
|
||||||
override def reads(json: JsValue): JsResult[SchnorrDigitalSignature] =
|
override def reads(json: JsValue): JsResult[SchnorrDigitalSignature] =
|
||||||
SerializerUtil.processJsString[SchnorrDigitalSignature](
|
SerializerUtil.processJsString[SchnorrDigitalSignature](
|
||||||
SchnorrDigitalSignature.fromHex)(json)
|
SchnorrDigitalSignature.fromHex
|
||||||
|
)(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object FieldElementReads extends Reads[FieldElement] {
|
implicit object FieldElementReads extends Reads[FieldElement] {
|
||||||
@ -423,7 +441,8 @@ object JsonReaders {
|
|||||||
|
|
||||||
override def reads(json: JsValue): JsResult[ScriptSignature] =
|
override def reads(json: JsValue): JsResult[ScriptSignature] =
|
||||||
SerializerUtil.processJsString[ScriptSignature](
|
SerializerUtil.processJsString[ScriptSignature](
|
||||||
ScriptSignature.fromAsmHex)(json)
|
ScriptSignature.fromAsmHex
|
||||||
|
)(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object TransactionInputReads extends Reads[TransactionInput] {
|
implicit object TransactionInputReads extends Reads[TransactionInput] {
|
||||||
@ -433,7 +452,8 @@ object JsonReaders {
|
|||||||
(json \ "coinbase").validate[String] match {
|
(json \ "coinbase").validate[String] match {
|
||||||
case s: JsSuccess[String] =>
|
case s: JsSuccess[String] =>
|
||||||
JsSuccess(
|
JsSuccess(
|
||||||
CoinbaseInput(ScriptSignature.fromAsmHex(s.value), sequence))
|
CoinbaseInput(ScriptSignature.fromAsmHex(s.value), sequence)
|
||||||
|
)
|
||||||
case _ =>
|
case _ =>
|
||||||
(json \ "txid").validate[DoubleSha256DigestBE].flatMap { txid =>
|
(json \ "txid").validate[DoubleSha256DigestBE].flatMap { txid =>
|
||||||
(json \ "vout").validate[UInt32].flatMap { vout =>
|
(json \ "vout").validate[UInt32].flatMap { vout =>
|
||||||
@ -441,9 +461,12 @@ object JsonReaders {
|
|||||||
.validate[ScriptSignature]
|
.validate[ScriptSignature]
|
||||||
.flatMap { scriptSig =>
|
.flatMap { scriptSig =>
|
||||||
JsSuccess(
|
JsSuccess(
|
||||||
TransactionInput(TransactionOutPoint(txid.flip, vout),
|
TransactionInput(
|
||||||
scriptSig,
|
TransactionOutPoint(txid.flip, vout),
|
||||||
sequence))
|
scriptSig,
|
||||||
|
sequence
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -510,7 +533,8 @@ object JsonReaders {
|
|||||||
case Some(JsNumber(n)) => JsSuccess(Bitcoins(n))
|
case Some(JsNumber(n)) => JsSuccess(Bitcoins(n))
|
||||||
case Some(
|
case Some(
|
||||||
err @ (JsNull | _: JsBoolean | _: JsString | _: JsArray |
|
err @ (JsNull | _: JsBoolean | _: JsString | _: JsArray |
|
||||||
_: JsObject)) =>
|
_: JsObject)
|
||||||
|
) =>
|
||||||
SerializerUtil.buildJsErrorMsg("jsnumber", err)
|
SerializerUtil.buildJsErrorMsg("jsnumber", err)
|
||||||
case None => JsError("error.expected.balance")
|
case None => JsError("error.expected.balance")
|
||||||
}
|
}
|
||||||
@ -605,9 +629,11 @@ object JsonReaders {
|
|||||||
pubkey <- (json \ "pubkey").validate[ECPublicKey]
|
pubkey <- (json \ "pubkey").validate[ECPublicKey]
|
||||||
masterFingerprint <- (json \ "master_fingerprint").validate[String]
|
masterFingerprint <- (json \ "master_fingerprint").validate[String]
|
||||||
path <- (json \ "path").validate[String]
|
path <- (json \ "path").validate[String]
|
||||||
} yield PsbtBIP32Deriv(pubkey = pubkey,
|
} yield PsbtBIP32Deriv(
|
||||||
masterFingerprint = masterFingerprint,
|
pubkey = pubkey,
|
||||||
path = path)
|
masterFingerprint = masterFingerprint,
|
||||||
|
path = path
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object RpcPsbtScriptReads extends Reads[RpcPsbtScript] {
|
implicit object RpcPsbtScriptReads extends Reads[RpcPsbtScript] {
|
||||||
@ -618,19 +644,24 @@ object JsonReaders {
|
|||||||
hex <- (json \ "hex").validate[ScriptPubKey]
|
hex <- (json \ "hex").validate[ScriptPubKey]
|
||||||
scriptType <- (json \ "type").validateOpt[ScriptType]
|
scriptType <- (json \ "type").validateOpt[ScriptType]
|
||||||
address <- (json \ "address").validateOpt[BitcoinAddress]
|
address <- (json \ "address").validateOpt[BitcoinAddress]
|
||||||
} yield RpcPsbtScript(asm = asm,
|
} yield RpcPsbtScript(
|
||||||
hex = hex,
|
asm = asm,
|
||||||
scriptType = scriptType,
|
hex = hex,
|
||||||
address = address)
|
scriptType = scriptType,
|
||||||
|
address = address
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object MapPubKeySignatureReads
|
implicit object MapPubKeySignatureReads
|
||||||
extends Reads[Map[ECPublicKey, ECDigitalSignature]] {
|
extends Reads[Map[ECPublicKey, ECDigitalSignature]] {
|
||||||
|
|
||||||
override def reads(
|
override def reads(
|
||||||
json: JsValue): JsResult[Map[ECPublicKey, ECDigitalSignature]] =
|
json: JsValue
|
||||||
JsonReaders.mapReads(json)(implicitly[Reads[ECPublicKey]],
|
): JsResult[Map[ECPublicKey, ECDigitalSignature]] =
|
||||||
implicitly[Reads[ECDigitalSignature]])
|
JsonReaders.mapReads(json)(
|
||||||
|
implicitly[Reads[ECPublicKey]],
|
||||||
|
implicitly[Reads[ECDigitalSignature]]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object RpcPsbtInputV22Reads extends Reads[RpcPsbtInputV22] {
|
implicit object RpcPsbtInputV22Reads extends Reads[RpcPsbtInputV22] {
|
||||||
@ -740,7 +771,8 @@ object JsonReaders {
|
|||||||
case Failure(err) =>
|
case Failure(err) =>
|
||||||
SerializerUtil.buildJsErrorMsg(
|
SerializerUtil.buildJsErrorMsg(
|
||||||
s"Unexpected Service Identifier: $err",
|
s"Unexpected Service Identifier: $err",
|
||||||
json)
|
json
|
||||||
|
)
|
||||||
}
|
}
|
||||||
case err @ (JsNull | _: JsBoolean | _: JsNumber | _: JsArray |
|
case err @ (JsNull | _: JsBoolean | _: JsNumber | _: JsArray |
|
||||||
_: JsObject) =>
|
_: JsObject) =>
|
||||||
@ -759,7 +791,8 @@ object JsonReaders {
|
|||||||
case Failure(err) =>
|
case Failure(err) =>
|
||||||
SerializerUtil.buildJsErrorMsg(
|
SerializerUtil.buildJsErrorMsg(
|
||||||
s"Unexpected Service Identifier: $err",
|
s"Unexpected Service Identifier: $err",
|
||||||
json)
|
json
|
||||||
|
)
|
||||||
}
|
}
|
||||||
case err @ (JsNull | _: JsBoolean | _: JsNumber | _: JsArray |
|
case err @ (JsNull | _: JsBoolean | _: JsNumber | _: JsArray |
|
||||||
_: JsObject) =>
|
_: JsObject) =>
|
||||||
@ -778,7 +811,8 @@ object JsonReaders {
|
|||||||
case Failure(err) =>
|
case Failure(err) =>
|
||||||
SerializerUtil.buildJsErrorMsg(
|
SerializerUtil.buildJsErrorMsg(
|
||||||
s"Unexpected Service Identifier: $err",
|
s"Unexpected Service Identifier: $err",
|
||||||
json)
|
json
|
||||||
|
)
|
||||||
}
|
}
|
||||||
case err @ (JsNull | _: JsBoolean | _: JsNumber | _: JsArray |
|
case err @ (JsNull | _: JsBoolean | _: JsNumber | _: JsArray |
|
||||||
_: JsObject) =>
|
_: JsObject) =>
|
||||||
@ -786,10 +820,11 @@ object JsonReaders {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val feeProportionalMillionthsReads: Reads[
|
implicit val feeProportionalMillionthsReads
|
||||||
FeeProportionalMillionths] = Reads { js =>
|
: Reads[FeeProportionalMillionths] = Reads { js =>
|
||||||
SerializerUtil.processJsNumberBigInt(FeeProportionalMillionths.fromBigInt)(
|
SerializerUtil.processJsNumberBigInt(FeeProportionalMillionths.fromBigInt)(
|
||||||
js)
|
js
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val channelStateReads: Reads[ChannelState] = {
|
implicit val channelStateReads: Reads[ChannelState] = {
|
||||||
@ -845,7 +880,8 @@ object JsonReaders {
|
|||||||
implicit val lnHrpReads: Reads[LnHumanReadablePart] = {
|
implicit val lnHrpReads: Reads[LnHumanReadablePart] = {
|
||||||
Reads { jsValue =>
|
Reads { jsValue =>
|
||||||
SerializerUtil.processJsStringOpt(LnHumanReadablePart.fromStringOpt(_))(
|
SerializerUtil.processJsStringOpt(LnHumanReadablePart.fromStringOpt(_))(
|
||||||
jsValue)
|
jsValue
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -861,7 +897,8 @@ object JsonReaders {
|
|||||||
addr.split(":") match {
|
addr.split(":") match {
|
||||||
case Array(host, portStr) =>
|
case Array(host, portStr) =>
|
||||||
val port = Try(portStr.toInt).getOrElse(
|
val port = Try(portStr.toInt).getOrElse(
|
||||||
throw new RuntimeException(s"Invalid port number `$portStr`"))
|
throw new RuntimeException(s"Invalid port number `$portStr`")
|
||||||
|
)
|
||||||
InetSocketAddress.createUnresolved(host, port.toInt)
|
InetSocketAddress.createUnresolved(host, port.toInt)
|
||||||
case _ => throw new RuntimeException(s"Invalid inet address `$addr`")
|
case _ => throw new RuntimeException(s"Invalid inet address `$addr`")
|
||||||
}
|
}
|
||||||
@ -922,7 +959,8 @@ object JsonReaders {
|
|||||||
implicit val shortChannelIdReads: Reads[ShortChannelId] = {
|
implicit val shortChannelIdReads: Reads[ShortChannelId] = {
|
||||||
Reads { jsValue =>
|
Reads { jsValue =>
|
||||||
SerializerUtil.processJsString(ShortChannelId.fromHumanReadableString)(
|
SerializerUtil.processJsString(ShortChannelId.fromHumanReadableString)(
|
||||||
jsValue)
|
jsValue
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -943,13 +981,15 @@ object JsonReaders {
|
|||||||
rgbColor <- (jsValue \ "rgbColor").validate[String]
|
rgbColor <- (jsValue \ "rgbColor").validate[String]
|
||||||
alias <- (jsValue \ "alias").validate[String]
|
alias <- (jsValue \ "alias").validate[String]
|
||||||
addresses <- (jsValue \ "addresses").validate[Vector[InetSocketAddress]]
|
addresses <- (jsValue \ "addresses").validate[Vector[InetSocketAddress]]
|
||||||
} yield NodeInfo(signature,
|
} yield NodeInfo(
|
||||||
features,
|
signature,
|
||||||
timestamp,
|
features,
|
||||||
nodeId,
|
timestamp,
|
||||||
rgbColor,
|
nodeId,
|
||||||
alias,
|
rgbColor,
|
||||||
addresses)
|
alias,
|
||||||
|
addresses
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -986,13 +1026,15 @@ object JsonReaders {
|
|||||||
description <- (jsValue \ "description").validate[String]
|
description <- (jsValue \ "description").validate[String]
|
||||||
paymentHash <- (jsValue \ "paymentHash").validate[Sha256Digest]
|
paymentHash <- (jsValue \ "paymentHash").validate[Sha256Digest]
|
||||||
expiry <- (jsValue \ "expiry").validate[Long]
|
expiry <- (jsValue \ "expiry").validate[Long]
|
||||||
} yield InvoiceResult(prefix,
|
} yield InvoiceResult(
|
||||||
timestamp,
|
prefix,
|
||||||
nodeId,
|
timestamp,
|
||||||
serialized,
|
nodeId,
|
||||||
description,
|
serialized,
|
||||||
paymentHash,
|
description,
|
||||||
expiry.seconds)
|
paymentHash,
|
||||||
|
expiry.seconds
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1010,12 +1052,14 @@ object JsonReaders {
|
|||||||
(jsValue \ "data" \ "commitments" \ "localCommit" \ "spec" \ "toLocal")
|
(jsValue \ "data" \ "commitments" \ "localCommit" \ "spec" \ "toLocal")
|
||||||
.validate[MilliSatoshis]
|
.validate[MilliSatoshis]
|
||||||
|
|
||||||
} yield OpenChannelInfo(nodeId = nodeId,
|
} yield OpenChannelInfo(
|
||||||
shortChannelId = shortChannelId,
|
nodeId = nodeId,
|
||||||
channelId = channelId,
|
shortChannelId = shortChannelId,
|
||||||
localMsat = localMsat,
|
channelId = channelId,
|
||||||
remoteMsat = remoteMsat,
|
localMsat = localMsat,
|
||||||
state = state)
|
remoteMsat = remoteMsat,
|
||||||
|
state = state
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val baseChannelInfoReads: Reads[BaseChannelInfo] = Reads { jsValue =>
|
implicit val baseChannelInfoReads: Reads[BaseChannelInfo] = Reads { jsValue =>
|
||||||
@ -1030,11 +1074,13 @@ object JsonReaders {
|
|||||||
(jsValue \ "data" \ "commitments" \ "localCommit" \ "spec" \ "toLocal")
|
(jsValue \ "data" \ "commitments" \ "localCommit" \ "spec" \ "toLocal")
|
||||||
.validate[MilliSatoshis]
|
.validate[MilliSatoshis]
|
||||||
|
|
||||||
} yield BaseChannelInfo(nodeId = nodeId,
|
} yield BaseChannelInfo(
|
||||||
channelId = channelId,
|
nodeId = nodeId,
|
||||||
localMsat = localMsat,
|
channelId = channelId,
|
||||||
remoteMsat = remoteMsat,
|
localMsat = localMsat,
|
||||||
state = state)
|
remoteMsat = remoteMsat,
|
||||||
|
state = state
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val channelInfoReads: Reads[ChannelInfo] = Reads { jsValue =>
|
implicit val channelInfoReads: Reads[ChannelInfo] = Reads { jsValue =>
|
||||||
@ -1078,12 +1124,14 @@ object JsonReaders {
|
|||||||
val result = Try(
|
val result = Try(
|
||||||
UpdateRelayFee.OK(
|
UpdateRelayFee.OK(
|
||||||
channelId = FundedChannelId.fromHex(
|
channelId = FundedChannelId.fromHex(
|
||||||
(x._2 \ "channelId").validate[String].get),
|
(x._2 \ "channelId").validate[String].get
|
||||||
|
),
|
||||||
feeBaseMsat =
|
feeBaseMsat =
|
||||||
(x._2 \ "cmd" \ "feeBase").validate[MilliSatoshis].get,
|
(x._2 \ "cmd" \ "feeBase").validate[MilliSatoshis].get,
|
||||||
feeProportionalMillionths =
|
feeProportionalMillionths =
|
||||||
(x._2 \ "cmd" \ "feeProportionalMillionths").validate[Long].get
|
(x._2 \ "cmd" \ "feeProportionalMillionths").validate[Long].get
|
||||||
)) match {
|
)
|
||||||
|
) match {
|
||||||
case Success(ok) => ok
|
case Success(ok) => ok
|
||||||
case Failure(_) => UpdateRelayFee.Error(x._2.toString())
|
case Failure(_) => UpdateRelayFee.Error(x._2.toString())
|
||||||
}
|
}
|
||||||
@ -1136,13 +1184,13 @@ object JsonReaders {
|
|||||||
implicit val sendToRouteResultReads: Reads[SendToRouteResult] =
|
implicit val sendToRouteResultReads: Reads[SendToRouteResult] =
|
||||||
Json.reads[SendToRouteResult]
|
Json.reads[SendToRouteResult]
|
||||||
|
|
||||||
//don't make this implicit so we don't accidentally read the wrong time unit
|
// don't make this implicit so we don't accidentally read the wrong time unit
|
||||||
val finiteDurationReadsMilliseconds: Reads[FiniteDuration] =
|
val finiteDurationReadsMilliseconds: Reads[FiniteDuration] =
|
||||||
Reads { js =>
|
Reads { js =>
|
||||||
SerializerUtil.processJsNumberBigInt(_.longValue.millis)(js)
|
SerializerUtil.processJsNumberBigInt(_.longValue.millis)(js)
|
||||||
}
|
}
|
||||||
|
|
||||||
//don't make this implicit so we don't accidentally read the wrong time unit
|
// don't make this implicit so we don't accidentally read the wrong time unit
|
||||||
val finiteDurationReadsSeconds: Reads[FiniteDuration] = Reads { js =>
|
val finiteDurationReadsSeconds: Reads[FiniteDuration] = Reads { js =>
|
||||||
SerializerUtil.processJsNumberBigInt(_.longValue.seconds)(js)
|
SerializerUtil.processJsNumberBigInt(_.longValue.seconds)(js)
|
||||||
}
|
}
|
||||||
@ -1182,10 +1230,12 @@ object JsonReaders {
|
|||||||
route <- (js \ "route").validate[Seq[Hop]]
|
route <- (js \ "route").validate[Seq[Hop]]
|
||||||
completed <- (js \ "completedAt" \ "unix")
|
completed <- (js \ "completedAt" \ "unix")
|
||||||
.validate[Instant](instantReadsMilliseconds)
|
.validate[Instant](instantReadsMilliseconds)
|
||||||
} yield OutgoingPaymentStatus.Succeeded(paymentPreimage = preimage,
|
} yield OutgoingPaymentStatus.Succeeded(
|
||||||
feesPaid = feesPaid,
|
paymentPreimage = preimage,
|
||||||
route = route,
|
feesPaid = feesPaid,
|
||||||
completedAt = completed)
|
route = route,
|
||||||
|
completedAt = completed
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val paymentFailureTypeReads: Reads[PaymentFailure.Type] = Reads {
|
implicit val paymentFailureTypeReads: Reads[PaymentFailure.Type] = Reads {
|
||||||
@ -1247,17 +1297,19 @@ object JsonReaders {
|
|||||||
amount <- (js \ "amount").validateOpt[MilliSatoshis]
|
amount <- (js \ "amount").validateOpt[MilliSatoshis]
|
||||||
minFinalCltvExpiry <- (js \ "minFinalCltvExpiry").validate[Int]
|
minFinalCltvExpiry <- (js \ "minFinalCltvExpiry").validate[Int]
|
||||||
features <- (js \ "features").validate[Features]
|
features <- (js \ "features").validate[Features]
|
||||||
} yield PaymentRequest(prefix,
|
} yield PaymentRequest(
|
||||||
timestamp,
|
prefix,
|
||||||
nodeId,
|
timestamp,
|
||||||
serialized,
|
nodeId,
|
||||||
description,
|
serialized,
|
||||||
paymentHash,
|
description,
|
||||||
paymentMetadata,
|
paymentHash,
|
||||||
expiry,
|
paymentMetadata,
|
||||||
minFinalCltvExpiry,
|
expiry,
|
||||||
amount,
|
minFinalCltvExpiry,
|
||||||
features)
|
amount,
|
||||||
|
features
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val paymentSucceededReads: Reads[OutgoingPayment] = Reads { js =>
|
implicit val paymentSucceededReads: Reads[OutgoingPayment] = Reads { js =>
|
||||||
@ -1274,17 +1326,19 @@ object JsonReaders {
|
|||||||
.validate[Instant](instantReadsMilliseconds)
|
.validate[Instant](instantReadsMilliseconds)
|
||||||
paymentRequest <- (js \ "paymentRequest").validateOpt[PaymentRequest]
|
paymentRequest <- (js \ "paymentRequest").validateOpt[PaymentRequest]
|
||||||
status <- (js \ "status").validate[OutgoingPaymentStatus]
|
status <- (js \ "status").validate[OutgoingPaymentStatus]
|
||||||
} yield OutgoingPayment(id,
|
} yield OutgoingPayment(
|
||||||
parentId,
|
id,
|
||||||
externalId,
|
parentId,
|
||||||
paymentHash,
|
externalId,
|
||||||
paymentType,
|
paymentHash,
|
||||||
amount,
|
paymentType,
|
||||||
recipientAmount,
|
amount,
|
||||||
recipientNodeId,
|
recipientAmount,
|
||||||
createdAt,
|
recipientNodeId,
|
||||||
paymentRequest,
|
createdAt,
|
||||||
status)
|
paymentRequest,
|
||||||
|
status
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val receivedPaymentResultReads: Reads[IncomingPayment] = Reads {
|
implicit val receivedPaymentResultReads: Reads[IncomingPayment] = Reads {
|
||||||
@ -1296,11 +1350,13 @@ object JsonReaders {
|
|||||||
createdAt <- (js \ "createdAt" \ "unix")
|
createdAt <- (js \ "createdAt" \ "unix")
|
||||||
.validate[Instant](instantReadsMilliseconds)
|
.validate[Instant](instantReadsMilliseconds)
|
||||||
status <- (js \ "status").validate[IncomingPaymentStatus]
|
status <- (js \ "status").validate[IncomingPaymentStatus]
|
||||||
} yield IncomingPayment(paymentRequest,
|
} yield IncomingPayment(
|
||||||
paymentPreimage,
|
paymentRequest,
|
||||||
paymentType,
|
paymentPreimage,
|
||||||
createdAt,
|
paymentType,
|
||||||
status)
|
createdAt,
|
||||||
|
status
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val channelResultReads: Reads[ChannelResult] = Reads { js =>
|
implicit val channelResultReads: Reads[ChannelResult] = Reads { js =>
|
||||||
@ -1314,12 +1370,14 @@ object JsonReaders {
|
|||||||
(js \ "data" \ "channelUpdate" \ "feeProportionalMillionths")
|
(js \ "data" \ "channelUpdate" \ "feeProportionalMillionths")
|
||||||
.validateOpt[FeeProportionalMillionths]
|
.validateOpt[FeeProportionalMillionths]
|
||||||
data <- (js \ "data").validate[JsObject]
|
data <- (js \ "data").validate[JsObject]
|
||||||
} yield ChannelResult(nodeId = nodeId,
|
} yield ChannelResult(
|
||||||
state = state,
|
nodeId = nodeId,
|
||||||
channelId = channelId,
|
state = state,
|
||||||
feeBaseMsat = feeBaseMsat,
|
channelId = channelId,
|
||||||
feeProportionalMillionths = feeProportional,
|
feeBaseMsat = feeBaseMsat,
|
||||||
data = data)
|
feeProportionalMillionths = feeProportional,
|
||||||
|
data = data
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val lnInvoiceReads: Reads[LnInvoice] =
|
implicit val lnInvoiceReads: Reads[LnInvoice] =
|
||||||
@ -1370,12 +1428,14 @@ object JsonReaders {
|
|||||||
toChannelId <- (js \ "toChannelId").validate[FundedChannelId]
|
toChannelId <- (js \ "toChannelId").validate[FundedChannelId]
|
||||||
timestamp <- (js \ "timestamp" \ "unix")
|
timestamp <- (js \ "timestamp" \ "unix")
|
||||||
.validate[Instant](instantReadsMilliseconds)
|
.validate[Instant](instantReadsMilliseconds)
|
||||||
} yield RelayedPayment(amountIn,
|
} yield RelayedPayment(
|
||||||
amountOut,
|
amountIn,
|
||||||
paymentHash,
|
amountOut,
|
||||||
fromChannelId,
|
paymentHash,
|
||||||
toChannelId,
|
fromChannelId,
|
||||||
timestamp)
|
toChannelId,
|
||||||
|
timestamp
|
||||||
|
)
|
||||||
}
|
}
|
||||||
implicit val auditResultReads: Reads[AuditResult] = Json.reads[AuditResult]
|
implicit val auditResultReads: Reads[AuditResult] = Json.reads[AuditResult]
|
||||||
|
|
||||||
@ -1388,12 +1448,14 @@ object JsonReaders {
|
|||||||
txType <- (js \ "txType").validate[String]
|
txType <- (js \ "txType").validate[String]
|
||||||
timestamp <- (js \ "timestamp" \ "unix")
|
timestamp <- (js \ "timestamp" \ "unix")
|
||||||
.validate[Instant](instantReadsMilliseconds)
|
.validate[Instant](instantReadsMilliseconds)
|
||||||
} yield NetworkFeesResult(remoteNodeId,
|
} yield NetworkFeesResult(
|
||||||
channelId,
|
remoteNodeId,
|
||||||
txId,
|
channelId,
|
||||||
fee,
|
txId,
|
||||||
txType,
|
fee,
|
||||||
timestamp)
|
txType,
|
||||||
|
timestamp
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val channelStatsDirectionReads: Reads[ChannelStats.Direction] =
|
implicit val channelStatsDirectionReads: Reads[ChannelStats.Direction] =
|
||||||
@ -1417,28 +1479,32 @@ object JsonReaders {
|
|||||||
toChannelId <- (js \ "toChannelId").validate[FundedChannelId]
|
toChannelId <- (js \ "toChannelId").validate[FundedChannelId]
|
||||||
timestamp <- (js \ "timestamp" \ "unix")
|
timestamp <- (js \ "timestamp" \ "unix")
|
||||||
.validate[Instant](instantReadsMilliseconds)
|
.validate[Instant](instantReadsMilliseconds)
|
||||||
} yield WebSocketEvent.PaymentRelayed(amountIn,
|
} yield WebSocketEvent.PaymentRelayed(
|
||||||
amountOut,
|
amountIn,
|
||||||
paymentHash,
|
amountOut,
|
||||||
fromChannelId,
|
paymentHash,
|
||||||
toChannelId,
|
fromChannelId,
|
||||||
timestamp)
|
toChannelId,
|
||||||
|
timestamp
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val paymentReceivedEventPartReads: Reads[
|
implicit val paymentReceivedEventPartReads
|
||||||
WebSocketEvent.PaymentReceived.Part] = Reads { js =>
|
: Reads[WebSocketEvent.PaymentReceived.Part] = Reads { js =>
|
||||||
for {
|
for {
|
||||||
amount <- (js \ "amount").validate[MilliSatoshis]
|
amount <- (js \ "amount").validate[MilliSatoshis]
|
||||||
fromChannelId <- (js \ "fromChannelId").validate[FundedChannelId]
|
fromChannelId <- (js \ "fromChannelId").validate[FundedChannelId]
|
||||||
timestamp <- (js \ "timestamp" \ "unix")
|
timestamp <- (js \ "timestamp" \ "unix")
|
||||||
.validate[Instant](instantReadsMilliseconds)
|
.validate[Instant](instantReadsMilliseconds)
|
||||||
} yield WebSocketEvent.PaymentReceived.Part(amount,
|
} yield WebSocketEvent.PaymentReceived.Part(
|
||||||
fromChannelId,
|
amount,
|
||||||
timestamp)
|
fromChannelId,
|
||||||
|
timestamp
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val paymentReceivedEventReads: Reads[
|
implicit val paymentReceivedEventReads
|
||||||
WebSocketEvent.PaymentReceived] = Reads { js =>
|
: Reads[WebSocketEvent.PaymentReceived] = Reads { js =>
|
||||||
for {
|
for {
|
||||||
paymentHash <- (js \ "paymentHash").validate[Sha256Digest]
|
paymentHash <- (js \ "paymentHash").validate[Sha256Digest]
|
||||||
parts <- (js \ "parts")
|
parts <- (js \ "parts")
|
||||||
@ -1454,14 +1520,16 @@ object JsonReaders {
|
|||||||
failures <- (js \ "failures").validate[Vector[JsObject]]
|
failures <- (js \ "failures").validate[Vector[JsObject]]
|
||||||
timestamp <- (js \ "timestamp" \ "unix")
|
timestamp <- (js \ "timestamp" \ "unix")
|
||||||
.validate[Instant](instantReadsMilliseconds)
|
.validate[Instant](instantReadsMilliseconds)
|
||||||
} yield WebSocketEvent.PaymentFailed(id,
|
} yield WebSocketEvent.PaymentFailed(
|
||||||
paymentHash,
|
id,
|
||||||
failures.map(_.toString()),
|
paymentHash,
|
||||||
timestamp)
|
failures.map(_.toString()),
|
||||||
|
timestamp
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val paymentSentEventPartReads: Reads[
|
implicit val paymentSentEventPartReads
|
||||||
WebSocketEvent.PaymentSent.Part] = Reads { js =>
|
: Reads[WebSocketEvent.PaymentSent.Part] = Reads { js =>
|
||||||
for {
|
for {
|
||||||
id <- (js \ "id").validate[PaymentId]
|
id <- (js \ "id").validate[PaymentId]
|
||||||
amount <- (js \ "amount").validate[MilliSatoshis]
|
amount <- (js \ "amount").validate[MilliSatoshis]
|
||||||
@ -1469,11 +1537,13 @@ object JsonReaders {
|
|||||||
toChannelId <- (js \ "toChannelId").validate[FundedChannelId]
|
toChannelId <- (js \ "toChannelId").validate[FundedChannelId]
|
||||||
timestamp <- (js \ "timestamp" \ "unix")
|
timestamp <- (js \ "timestamp" \ "unix")
|
||||||
.validate[Instant](instantReadsMilliseconds)
|
.validate[Instant](instantReadsMilliseconds)
|
||||||
} yield WebSocketEvent.PaymentSent.Part(id,
|
} yield WebSocketEvent.PaymentSent.Part(
|
||||||
amount,
|
id,
|
||||||
feesPaid,
|
amount,
|
||||||
toChannelId,
|
feesPaid,
|
||||||
timestamp)
|
toChannelId,
|
||||||
|
timestamp
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val paymentSentEventReads: Reads[WebSocketEvent.PaymentSent] =
|
implicit val paymentSentEventReads: Reads[WebSocketEvent.PaymentSent] =
|
||||||
@ -1484,22 +1554,26 @@ object JsonReaders {
|
|||||||
paymentPreimage <- (js \ "paymentPreimage").validate[PaymentPreimage]
|
paymentPreimage <- (js \ "paymentPreimage").validate[PaymentPreimage]
|
||||||
parts <- (js \ "parts")
|
parts <- (js \ "parts")
|
||||||
.validate[Vector[WebSocketEvent.PaymentSent.Part]]
|
.validate[Vector[WebSocketEvent.PaymentSent.Part]]
|
||||||
} yield WebSocketEvent.PaymentSent(id,
|
} yield WebSocketEvent.PaymentSent(
|
||||||
paymentHash,
|
id,
|
||||||
paymentPreimage,
|
paymentHash,
|
||||||
parts)
|
paymentPreimage,
|
||||||
|
parts
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val paymentSettlingOnchainEventReads: Reads[
|
implicit val paymentSettlingOnchainEventReads
|
||||||
WebSocketEvent.PaymentSettlingOnchain] = Reads { js =>
|
: Reads[WebSocketEvent.PaymentSettlingOnchain] = Reads { js =>
|
||||||
for {
|
for {
|
||||||
amount <- (js \ "amount").validate[MilliSatoshis]
|
amount <- (js \ "amount").validate[MilliSatoshis]
|
||||||
paymentHash <- (js \ "paymentHash").validate[Sha256Digest]
|
paymentHash <- (js \ "paymentHash").validate[Sha256Digest]
|
||||||
timestamp <- (js \ "timestamp" \ "unix")
|
timestamp <- (js \ "timestamp" \ "unix")
|
||||||
.validate[Instant](instantReadsMilliseconds)
|
.validate[Instant](instantReadsMilliseconds)
|
||||||
} yield WebSocketEvent.PaymentSettlingOnchain(amount,
|
} yield WebSocketEvent.PaymentSettlingOnchain(
|
||||||
paymentHash,
|
amount,
|
||||||
timestamp)
|
paymentHash,
|
||||||
|
timestamp
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val webSocketEventReads: Reads[WebSocketEvent] =
|
implicit val webSocketEventReads: Reads[WebSocketEvent] =
|
||||||
@ -1549,7 +1623,8 @@ object JsonReaders {
|
|||||||
implicit val connectionDirectionReads: Reads[ConnectionDirection] = {
|
implicit val connectionDirectionReads: Reads[ConnectionDirection] = {
|
||||||
Reads { jsValue =>
|
Reads { jsValue =>
|
||||||
SerializerUtil.processJsStringOpt(ConnectionDirection.fromStringOpt)(
|
SerializerUtil.processJsStringOpt(ConnectionDirection.fromStringOpt)(
|
||||||
jsValue)
|
jsValue
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1568,7 +1643,8 @@ object JsonReaders {
|
|||||||
implicit val closedChannelTypeReads: Reads[ClosedChannelType] = {
|
implicit val closedChannelTypeReads: Reads[ClosedChannelType] = {
|
||||||
Reads { jsValue =>
|
Reads { jsValue =>
|
||||||
SerializerUtil.processJsStringOpt(ClosedChannelType.fromStringOpt)(
|
SerializerUtil.processJsStringOpt(ClosedChannelType.fromStringOpt)(
|
||||||
jsValue)
|
jsValue
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,8 +136,8 @@ object JsonSerializers {
|
|||||||
.readNullable[Vector[BitcoinAddress]] and
|
.readNullable[Vector[BitcoinAddress]] and
|
||||||
(__ \ "address").readNullable[BitcoinAddress])(RpcScriptPubKeyPostV22)
|
(__ \ "address").readNullable[BitcoinAddress])(RpcScriptPubKeyPostV22)
|
||||||
|
|
||||||
implicit val rpcTransactionOutputPreV22Reads: Reads[
|
implicit val rpcTransactionOutputPreV22Reads
|
||||||
RpcTransactionOutputPreV22] =
|
: Reads[RpcTransactionOutputPreV22] =
|
||||||
Json.reads[RpcTransactionOutputPreV22]
|
Json.reads[RpcTransactionOutputPreV22]
|
||||||
|
|
||||||
implicit val rpcTransactionOutputV22Reads: Reads[RpcTransactionOutputV22] =
|
implicit val rpcTransactionOutputV22Reads: Reads[RpcTransactionOutputV22] =
|
||||||
@ -154,18 +154,19 @@ object JsonSerializers {
|
|||||||
implicit val fundRawTransactionResultReads: Reads[FundRawTransactionResult] =
|
implicit val fundRawTransactionResultReads: Reads[FundRawTransactionResult] =
|
||||||
Json.reads[FundRawTransactionResult]
|
Json.reads[FundRawTransactionResult]
|
||||||
|
|
||||||
implicit val signRawTransactionWithWalletResultReads: Reads[
|
implicit val signRawTransactionWithWalletResultReads
|
||||||
SignRawTransactionWithWalletResult] =
|
: Reads[SignRawTransactionWithWalletResult] =
|
||||||
Json.reads[SignRawTransactionWithWalletResult]
|
Json.reads[SignRawTransactionWithWalletResult]
|
||||||
|
|
||||||
implicit val getRawTransactionScriptSigReads: Reads[
|
implicit val getRawTransactionScriptSigReads
|
||||||
GetRawTransactionScriptSig] = Json.reads[GetRawTransactionScriptSig]
|
: Reads[GetRawTransactionScriptSig] =
|
||||||
|
Json.reads[GetRawTransactionScriptSig]
|
||||||
|
|
||||||
implicit val getRawTransactionVinReads: Reads[GetRawTransactionVin] =
|
implicit val getRawTransactionVinReads: Reads[GetRawTransactionVin] =
|
||||||
Json.reads[GetRawTransactionVin]
|
Json.reads[GetRawTransactionVin]
|
||||||
|
|
||||||
implicit val getRawTransactionResultV22Reads: Reads[
|
implicit val getRawTransactionResultV22Reads
|
||||||
GetRawTransactionResultV22] =
|
: Reads[GetRawTransactionResultV22] =
|
||||||
Json.reads[GetRawTransactionResultV22]
|
Json.reads[GetRawTransactionResultV22]
|
||||||
|
|
||||||
implicit val signRawTransactionErrorReads: Reads[SignRawTransactionError] =
|
implicit val signRawTransactionErrorReads: Reads[SignRawTransactionError] =
|
||||||
@ -258,8 +259,8 @@ object JsonSerializers {
|
|||||||
implicit val getBlockResultReads: Reads[GetBlockResult] =
|
implicit val getBlockResultReads: Reads[GetBlockResult] =
|
||||||
Json.reads[GetBlockResult]
|
Json.reads[GetBlockResult]
|
||||||
|
|
||||||
implicit val getBlockWithTransactionsResultV22Reads: Reads[
|
implicit val getBlockWithTransactionsResultV22Reads
|
||||||
GetBlockWithTransactionsResultV22] =
|
: Reads[GetBlockWithTransactionsResultV22] =
|
||||||
Json.reads[GetBlockWithTransactionsResultV22]
|
Json.reads[GetBlockWithTransactionsResultV22]
|
||||||
|
|
||||||
implicit val softforkProgressPreV19Reads: Reads[SoftforkProgressPreV19] =
|
implicit val softforkProgressPreV19Reads: Reads[SoftforkProgressPreV19] =
|
||||||
@ -271,8 +272,8 @@ object JsonSerializers {
|
|||||||
implicit val bip9SoftforkPreV19Reads: Reads[Bip9SoftforkPreV19] =
|
implicit val bip9SoftforkPreV19Reads: Reads[Bip9SoftforkPreV19] =
|
||||||
Json.reads[Bip9SoftforkPreV19]
|
Json.reads[Bip9SoftforkPreV19]
|
||||||
|
|
||||||
implicit val getBlockChainInfoResultPreV19Reads: Reads[
|
implicit val getBlockChainInfoResultPreV19Reads
|
||||||
GetBlockChainInfoResultPreV19] =
|
: Reads[GetBlockChainInfoResultPreV19] =
|
||||||
Json.reads[GetBlockChainInfoResultPreV19]
|
Json.reads[GetBlockChainInfoResultPreV19]
|
||||||
|
|
||||||
implicit val bip9SoftforkDetailsReads: Reads[Bip9SoftforkDetails] =
|
implicit val bip9SoftforkDetailsReads: Reads[Bip9SoftforkDetails] =
|
||||||
@ -286,11 +287,13 @@ object JsonSerializers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val getBlockChainInfoResultPostV19Reads: Reads[
|
implicit val getBlockChainInfoResultPostV19Reads
|
||||||
GetBlockChainInfoResultPostV19] = Json.reads[GetBlockChainInfoResultPostV19]
|
: Reads[GetBlockChainInfoResultPostV19] =
|
||||||
|
Json.reads[GetBlockChainInfoResultPostV19]
|
||||||
|
|
||||||
implicit val getBlockChainInfoResultPostV23Reads: Reads[
|
implicit val getBlockChainInfoResultPostV23Reads
|
||||||
GetBlockChainInfoResultPostV23] = Json.reads[GetBlockChainInfoResultPostV23]
|
: Reads[GetBlockChainInfoResultPostV23] =
|
||||||
|
Json.reads[GetBlockChainInfoResultPostV23]
|
||||||
|
|
||||||
implicit val blockHeaderFormattedReads: Reads[GetBlockHeaderResult] =
|
implicit val blockHeaderFormattedReads: Reads[GetBlockHeaderResult] =
|
||||||
Json.reads[GetBlockHeaderResult]
|
Json.reads[GetBlockHeaderResult]
|
||||||
@ -311,16 +314,16 @@ object JsonSerializers {
|
|||||||
implicit val getMemPoolResultPostV23Reads: Reads[GetMemPoolResultPostV23] =
|
implicit val getMemPoolResultPostV23Reads: Reads[GetMemPoolResultPostV23] =
|
||||||
Json.reads[GetMemPoolResultPostV23]
|
Json.reads[GetMemPoolResultPostV23]
|
||||||
|
|
||||||
implicit val getMemPoolEntryResultPreV19Reads: Reads[
|
implicit val getMemPoolEntryResultPreV19Reads
|
||||||
GetMemPoolEntryResultPreV19] =
|
: Reads[GetMemPoolEntryResultPreV19] =
|
||||||
Json.reads[GetMemPoolEntryResultPreV19]
|
Json.reads[GetMemPoolEntryResultPreV19]
|
||||||
|
|
||||||
implicit val getMemPoolEntryResultPostV19Reads: Reads[
|
implicit val getMemPoolEntryResultPostV19Reads
|
||||||
GetMemPoolEntryResultPostV19] =
|
: Reads[GetMemPoolEntryResultPostV19] =
|
||||||
Json.reads[GetMemPoolEntryResultPostV19]
|
Json.reads[GetMemPoolEntryResultPostV19]
|
||||||
|
|
||||||
implicit val getMemPoolEntryResultPostV23Reads: Reads[
|
implicit val getMemPoolEntryResultPostV23Reads
|
||||||
GetMemPoolEntryResultPostV23] =
|
: Reads[GetMemPoolEntryResultPostV23] =
|
||||||
Json.reads[GetMemPoolEntryResultPostV23]
|
Json.reads[GetMemPoolEntryResultPostV23]
|
||||||
|
|
||||||
implicit val getMemPoolInfoResultReads: Reads[GetMemPoolInfoResult] =
|
implicit val getMemPoolInfoResultReads: Reads[GetMemPoolInfoResult] =
|
||||||
@ -332,12 +335,12 @@ object JsonSerializers {
|
|||||||
implicit val getTxOutSetInfoResultReads: Reads[GetTxOutSetInfoResult] =
|
implicit val getTxOutSetInfoResultReads: Reads[GetTxOutSetInfoResult] =
|
||||||
Json.reads[GetTxOutSetInfoResult]
|
Json.reads[GetTxOutSetInfoResult]
|
||||||
|
|
||||||
implicit val GetTxSpendingPrevOutResultReads: Reads[
|
implicit val GetTxSpendingPrevOutResultReads
|
||||||
GetTxSpendingPrevOutResult] =
|
: Reads[GetTxSpendingPrevOutResult] =
|
||||||
Json.reads[GetTxSpendingPrevOutResult]
|
Json.reads[GetTxSpendingPrevOutResult]
|
||||||
|
|
||||||
implicit val SimulateRawTransactionResultReads: Reads[
|
implicit val SimulateRawTransactionResultReads
|
||||||
SimulateRawTransactionResult] =
|
: Reads[SimulateRawTransactionResult] =
|
||||||
Json.reads[SimulateRawTransactionResult]
|
Json.reads[SimulateRawTransactionResult]
|
||||||
|
|
||||||
implicit object Bip32PathFormats extends Format[BIP32Path] {
|
implicit object Bip32PathFormats extends Format[BIP32Path] {
|
||||||
@ -383,8 +386,8 @@ object JsonSerializers {
|
|||||||
(__ \ "details").read[Vector[TransactionDetails]] and
|
(__ \ "details").read[Vector[TransactionDetails]] and
|
||||||
(__ \ "hex").read[Transaction])(GetTransactionResult)
|
(__ \ "hex").read[Transaction])(GetTransactionResult)
|
||||||
|
|
||||||
implicit val getWalletInfoResultReadsPostV22: Reads[
|
implicit val getWalletInfoResultReadsPostV22
|
||||||
GetWalletInfoResultPostV22] =
|
: Reads[GetWalletInfoResultPostV22] =
|
||||||
Json.reads[GetWalletInfoResultPostV22]
|
Json.reads[GetWalletInfoResultPostV22]
|
||||||
|
|
||||||
implicit val importMultiErrorReads: Reads[ImportMultiError] =
|
implicit val importMultiErrorReads: Reads[ImportMultiError] =
|
||||||
@ -530,8 +533,8 @@ object JsonSerializers {
|
|||||||
implicit val addressInfoResultPreV18Reads: Reads[AddressInfoResultPreV18] =
|
implicit val addressInfoResultPreV18Reads: Reads[AddressInfoResultPreV18] =
|
||||||
Json.reads[AddressInfoResultPreV18]
|
Json.reads[AddressInfoResultPreV18]
|
||||||
|
|
||||||
implicit val addressInfoResultPostV18Reads: Reads[
|
implicit val addressInfoResultPostV18Reads
|
||||||
AddressInfoResultPostV18] = {
|
: Reads[AddressInfoResultPostV18] = {
|
||||||
Reads[AddressInfoResultPostV18] { json =>
|
Reads[AddressInfoResultPostV18] { json =>
|
||||||
for {
|
for {
|
||||||
isProps <-
|
isProps <-
|
||||||
@ -539,7 +542,8 @@ object JsonSerializers {
|
|||||||
infoWithoutProps <-
|
infoWithoutProps <-
|
||||||
Json
|
Json
|
||||||
.reads[
|
.reads[
|
||||||
AddressInfoResultPostV18.AddressInfoResultPostV18WithoutIsProps]
|
AddressInfoResultPostV18.AddressInfoResultPostV18WithoutIsProps
|
||||||
|
]
|
||||||
.reads(json)
|
.reads(json)
|
||||||
} yield {
|
} yield {
|
||||||
AddressInfoResultPostV18(infoWithoutProps, isProps)
|
AddressInfoResultPostV18(infoWithoutProps, isProps)
|
||||||
@ -547,8 +551,8 @@ object JsonSerializers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val addressInfoResultPostV21Reads: Reads[
|
implicit val addressInfoResultPostV21Reads
|
||||||
AddressInfoResultPostV21] = {
|
: Reads[AddressInfoResultPostV21] = {
|
||||||
Reads[AddressInfoResultPostV21] { json =>
|
Reads[AddressInfoResultPostV21] { json =>
|
||||||
for {
|
for {
|
||||||
isProps <-
|
isProps <-
|
||||||
@ -556,7 +560,8 @@ object JsonSerializers {
|
|||||||
infoWithoutProps <-
|
infoWithoutProps <-
|
||||||
Json
|
Json
|
||||||
.reads[
|
.reads[
|
||||||
AddressInfoResultPostV21.AddressInfoResultPostV21WithoutIsProps]
|
AddressInfoResultPostV21.AddressInfoResultPostV21WithoutIsProps
|
||||||
|
]
|
||||||
.reads(json)
|
.reads(json)
|
||||||
} yield {
|
} yield {
|
||||||
AddressInfoResultPostV21(infoWithoutProps, isProps)
|
AddressInfoResultPostV21(infoWithoutProps, isProps)
|
||||||
@ -591,8 +596,8 @@ object JsonSerializers {
|
|||||||
implicit val psbtWitnessUtxoInputReads: Reads[PsbtWitnessUtxoInput] =
|
implicit val psbtWitnessUtxoInputReads: Reads[PsbtWitnessUtxoInput] =
|
||||||
Json.reads[PsbtWitnessUtxoInput]
|
Json.reads[PsbtWitnessUtxoInput]
|
||||||
|
|
||||||
implicit val mapPubKeySignatureReads: Reads[
|
implicit val mapPubKeySignatureReads
|
||||||
Map[ECPublicKey, ECDigitalSignature]] = MapPubKeySignatureReads
|
: Reads[Map[ECPublicKey, ECDigitalSignature]] = MapPubKeySignatureReads
|
||||||
|
|
||||||
implicit val rpcPsbtInputV22Reads: Reads[RpcPsbtInputV22] =
|
implicit val rpcPsbtInputV22Reads: Reads[RpcPsbtInputV22] =
|
||||||
RpcPsbtInputV22Reads
|
RpcPsbtInputV22Reads
|
||||||
@ -609,8 +614,8 @@ object JsonSerializers {
|
|||||||
implicit val analyzePsbtResultReads: Reads[AnalyzePsbtResult] =
|
implicit val analyzePsbtResultReads: Reads[AnalyzePsbtResult] =
|
||||||
Json.reads[AnalyzePsbtResult]
|
Json.reads[AnalyzePsbtResult]
|
||||||
|
|
||||||
implicit val getNodeAddressesPostV22Reads: Reads[
|
implicit val getNodeAddressesPostV22Reads
|
||||||
GetNodeAddressesResultPostV22] =
|
: Reads[GetNodeAddressesResultPostV22] =
|
||||||
Reads[GetNodeAddressesResultPostV22] { js =>
|
Reads[GetNodeAddressesResultPostV22] { js =>
|
||||||
for {
|
for {
|
||||||
time <- (js \ "time").validate[Long].map(_.seconds)
|
time <- (js \ "time").validate[Long].map(_.seconds)
|
||||||
@ -618,11 +623,13 @@ object JsonSerializers {
|
|||||||
address <- (js \ "address").validate[URI]
|
address <- (js \ "address").validate[URI]
|
||||||
port <- (js \ "port").validate[Int]
|
port <- (js \ "port").validate[Int]
|
||||||
network <- (js \ "network").validate[String]
|
network <- (js \ "network").validate[String]
|
||||||
} yield GetNodeAddressesResultPostV22(time,
|
} yield GetNodeAddressesResultPostV22(
|
||||||
services,
|
time,
|
||||||
address,
|
services,
|
||||||
port,
|
address,
|
||||||
network)
|
port,
|
||||||
|
network
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val rgetpcCommandsReads: Reads[RpcCommands] = Reads[RpcCommands] {
|
implicit val rgetpcCommandsReads: Reads[RpcCommands] = Reads[RpcCommands] {
|
||||||
@ -648,8 +655,8 @@ object JsonSerializers {
|
|||||||
implicit val getDescriptorInfoResultReads: Reads[GetDescriptorInfoResult] =
|
implicit val getDescriptorInfoResultReads: Reads[GetDescriptorInfoResult] =
|
||||||
Json.reads[GetDescriptorInfoResult]
|
Json.reads[GetDescriptorInfoResult]
|
||||||
|
|
||||||
implicit val walletCreateFundedPsbtResultReads: Reads[
|
implicit val walletCreateFundedPsbtResultReads
|
||||||
WalletCreateFundedPsbtResult] =
|
: Reads[WalletCreateFundedPsbtResult] =
|
||||||
Json.reads[WalletCreateFundedPsbtResult]
|
Json.reads[WalletCreateFundedPsbtResult]
|
||||||
|
|
||||||
implicit val scriptTypeReads: Reads[ScriptType] = ScriptTypeReads
|
implicit val scriptTypeReads: Reads[ScriptType] = ScriptTypeReads
|
||||||
@ -659,8 +666,9 @@ object JsonSerializers {
|
|||||||
|
|
||||||
implicit val FeeInfoTwoReads: Reads[FeeInfoTwo] = Json.reads[FeeInfoTwo]
|
implicit val FeeInfoTwoReads: Reads[FeeInfoTwo] = Json.reads[FeeInfoTwo]
|
||||||
|
|
||||||
implicit val testMempoolAcceptResultReadsPostV22: Reads[
|
implicit val testMempoolAcceptResultReadsPostV22
|
||||||
TestMempoolAcceptResultPostV22] = Json.reads[TestMempoolAcceptResultPostV22]
|
: Reads[TestMempoolAcceptResultPostV22] =
|
||||||
|
Json.reads[TestMempoolAcceptResultPostV22]
|
||||||
|
|
||||||
implicit val indexInfoResultReads: Reads[IndexInfoResult] =
|
implicit val indexInfoResultReads: Reads[IndexInfoResult] =
|
||||||
Json.reads[IndexInfoResult]
|
Json.reads[IndexInfoResult]
|
||||||
@ -719,12 +727,12 @@ object JsonSerializers {
|
|||||||
implicit val cLightningInvoiceResultReads: Reads[CLightningInvoiceResult] =
|
implicit val cLightningInvoiceResultReads: Reads[CLightningInvoiceResult] =
|
||||||
Json.reads[CLightningInvoiceResult]
|
Json.reads[CLightningInvoiceResult]
|
||||||
|
|
||||||
implicit val cLightningLookupInvoiceResultReads: Reads[
|
implicit val cLightningLookupInvoiceResultReads
|
||||||
CLightningLookupInvoiceResult] =
|
: Reads[CLightningLookupInvoiceResult] =
|
||||||
Json.reads[CLightningLookupInvoiceResult]
|
Json.reads[CLightningLookupInvoiceResult]
|
||||||
|
|
||||||
implicit val cLightningListInvoicesResultReads: Reads[
|
implicit val cLightningListInvoicesResultReads
|
||||||
CLightningListInvoicesResult] =
|
: Reads[CLightningListInvoicesResult] =
|
||||||
Json.reads[CLightningListInvoicesResult]
|
Json.reads[CLightningListInvoicesResult]
|
||||||
|
|
||||||
implicit val cLightningPayResultReads: Reads[CLightningPayResult] =
|
implicit val cLightningPayResultReads: Reads[CLightningPayResult] =
|
||||||
@ -745,23 +753,23 @@ object JsonSerializers {
|
|||||||
implicit val cLightningWithdrawResultReads: Reads[WithdrawResult] =
|
implicit val cLightningWithdrawResultReads: Reads[WithdrawResult] =
|
||||||
Json.reads[WithdrawResult]
|
Json.reads[WithdrawResult]
|
||||||
|
|
||||||
implicit val cLightningFundChannelStartResultReads: Reads[
|
implicit val cLightningFundChannelStartResultReads
|
||||||
FundChannelStartResult] =
|
: Reads[FundChannelStartResult] =
|
||||||
Json.reads[FundChannelStartResult]
|
Json.reads[FundChannelStartResult]
|
||||||
|
|
||||||
implicit val cLightningFundChannelCompleteResultReads: Reads[
|
implicit val cLightningFundChannelCompleteResultReads
|
||||||
FundChannelCompleteResult] =
|
: Reads[FundChannelCompleteResult] =
|
||||||
Json.reads[FundChannelCompleteResult]
|
Json.reads[FundChannelCompleteResult]
|
||||||
|
|
||||||
implicit val cLightningFundChannelCancelResultReads: Reads[
|
implicit val cLightningFundChannelCancelResultReads
|
||||||
FundChannelCancelResult] =
|
: Reads[FundChannelCancelResult] =
|
||||||
Json.reads[FundChannelCancelResult]
|
Json.reads[FundChannelCancelResult]
|
||||||
|
|
||||||
implicit val CLightningTransactionReads: Reads[CLightningTransaction] =
|
implicit val CLightningTransactionReads: Reads[CLightningTransaction] =
|
||||||
Json.reads[CLightningTransaction]
|
Json.reads[CLightningTransaction]
|
||||||
|
|
||||||
implicit val CLightningListTransactionsResultsReads: Reads[
|
implicit val CLightningListTransactionsResultsReads
|
||||||
ListTransactionsResults] =
|
: Reads[ListTransactionsResults] =
|
||||||
Json.reads[ListTransactionsResults]
|
Json.reads[ListTransactionsResults]
|
||||||
|
|
||||||
implicit val SendCustomMessageResultReads: Reads[SendCustomMessageResult] =
|
implicit val SendCustomMessageResultReads: Reads[SendCustomMessageResult] =
|
||||||
@ -788,14 +796,17 @@ object JsonSerializers {
|
|||||||
implicit val int32Writes: Writes[Int32] =
|
implicit val int32Writes: Writes[Int32] =
|
||||||
Writes[Int32](num => JsNumber(num.toLong))
|
Writes[Int32](num => JsNumber(num.toLong))
|
||||||
|
|
||||||
implicit val serializedTransactionWitnessWrites: Writes[
|
implicit val serializedTransactionWitnessWrites
|
||||||
SerializedTransactionWitness] = Json.writes[SerializedTransactionWitness]
|
: Writes[SerializedTransactionWitness] =
|
||||||
|
Json.writes[SerializedTransactionWitness]
|
||||||
|
|
||||||
implicit val serializedTransactionInputWrites: Writes[
|
implicit val serializedTransactionInputWrites
|
||||||
SerializedTransactionInput] = Json.writes[SerializedTransactionInput]
|
: Writes[SerializedTransactionInput] =
|
||||||
|
Json.writes[SerializedTransactionInput]
|
||||||
|
|
||||||
implicit val serializedTransactionOutputWrites: Writes[
|
implicit val serializedTransactionOutputWrites
|
||||||
SerializedTransactionOutput] = Json.writes[SerializedTransactionOutput]
|
: Writes[SerializedTransactionOutput] =
|
||||||
|
Json.writes[SerializedTransactionOutput]
|
||||||
|
|
||||||
implicit val serializedTransactionWrites: Writes[SerializedTransaction] =
|
implicit val serializedTransactionWrites: Writes[SerializedTransaction] =
|
||||||
Json.writes[SerializedTransaction]
|
Json.writes[SerializedTransaction]
|
||||||
@ -822,46 +833,46 @@ object JsonSerializers {
|
|||||||
Json.writes[SerializedPSBT]
|
Json.writes[SerializedPSBT]
|
||||||
|
|
||||||
// Map stuff
|
// Map stuff
|
||||||
implicit def mapDoubleSha256DigestReadsPreV19: Reads[
|
implicit def mapDoubleSha256DigestReadsPreV19
|
||||||
Map[DoubleSha256Digest, GetMemPoolResultPreV19]] =
|
: Reads[Map[DoubleSha256Digest, GetMemPoolResultPreV19]] =
|
||||||
Reads.mapReads[DoubleSha256Digest, GetMemPoolResultPreV19](s =>
|
Reads.mapReads[DoubleSha256Digest, GetMemPoolResultPreV19](s =>
|
||||||
JsSuccess(DoubleSha256Digest.fromHex(s)))
|
JsSuccess(DoubleSha256Digest.fromHex(s)))
|
||||||
|
|
||||||
implicit def mapDoubleSha256DigestReadsPostV19: Reads[
|
implicit def mapDoubleSha256DigestReadsPostV19
|
||||||
Map[DoubleSha256Digest, GetMemPoolResultPostV19]] =
|
: Reads[Map[DoubleSha256Digest, GetMemPoolResultPostV19]] =
|
||||||
Reads.mapReads[DoubleSha256Digest, GetMemPoolResultPostV19](s =>
|
Reads.mapReads[DoubleSha256Digest, GetMemPoolResultPostV19](s =>
|
||||||
JsSuccess(DoubleSha256Digest.fromHex(s)))
|
JsSuccess(DoubleSha256Digest.fromHex(s)))
|
||||||
|
|
||||||
implicit def mapDoubleSha256DigestReadsPostV23: Reads[
|
implicit def mapDoubleSha256DigestReadsPostV23
|
||||||
Map[DoubleSha256Digest, GetMemPoolResultPostV23]] =
|
: Reads[Map[DoubleSha256Digest, GetMemPoolResultPostV23]] =
|
||||||
Reads.mapReads[DoubleSha256Digest, GetMemPoolResultPostV23](s =>
|
Reads.mapReads[DoubleSha256Digest, GetMemPoolResultPostV23](s =>
|
||||||
JsSuccess(DoubleSha256Digest.fromHex(s)))
|
JsSuccess(DoubleSha256Digest.fromHex(s)))
|
||||||
|
|
||||||
implicit def mapDoubleSha256DigestBEReadsPreV19: Reads[
|
implicit def mapDoubleSha256DigestBEReadsPreV19
|
||||||
Map[DoubleSha256DigestBE, GetMemPoolResultPreV19]] =
|
: Reads[Map[DoubleSha256DigestBE, GetMemPoolResultPreV19]] =
|
||||||
Reads.mapReads[DoubleSha256DigestBE, GetMemPoolResultPreV19](s =>
|
Reads.mapReads[DoubleSha256DigestBE, GetMemPoolResultPreV19](s =>
|
||||||
JsSuccess(DoubleSha256DigestBE.fromHex(s)))
|
JsSuccess(DoubleSha256DigestBE.fromHex(s)))
|
||||||
|
|
||||||
implicit def mapDoubleSha256DigestBEReadsPostV19: Reads[
|
implicit def mapDoubleSha256DigestBEReadsPostV19
|
||||||
Map[DoubleSha256DigestBE, GetMemPoolResultPostV19]] =
|
: Reads[Map[DoubleSha256DigestBE, GetMemPoolResultPostV19]] =
|
||||||
Reads.mapReads[DoubleSha256DigestBE, GetMemPoolResultPostV19](s =>
|
Reads.mapReads[DoubleSha256DigestBE, GetMemPoolResultPostV19](s =>
|
||||||
JsSuccess(DoubleSha256DigestBE.fromHex(s)))
|
JsSuccess(DoubleSha256DigestBE.fromHex(s)))
|
||||||
|
|
||||||
implicit def mapDoubleSha256DigestBEReadsPostV23: Reads[
|
implicit def mapDoubleSha256DigestBEReadsPostV23
|
||||||
Map[DoubleSha256DigestBE, GetMemPoolResultPostV23]] =
|
: Reads[Map[DoubleSha256DigestBE, GetMemPoolResultPostV23]] =
|
||||||
Reads.mapReads[DoubleSha256DigestBE, GetMemPoolResultPostV23](s =>
|
Reads.mapReads[DoubleSha256DigestBE, GetMemPoolResultPostV23](s =>
|
||||||
JsSuccess(DoubleSha256DigestBE.fromHex(s)))
|
JsSuccess(DoubleSha256DigestBE.fromHex(s)))
|
||||||
|
|
||||||
implicit def mapAddressesByLabelReads: Reads[
|
implicit def mapAddressesByLabelReads
|
||||||
Map[BitcoinAddress, LabelResult]] =
|
: Reads[Map[BitcoinAddress, LabelResult]] =
|
||||||
Reads.mapReads[BitcoinAddress, LabelResult](s =>
|
Reads.mapReads[BitcoinAddress, LabelResult](s =>
|
||||||
JsSuccess(BitcoinAddress.fromString(s)))
|
JsSuccess(BitcoinAddress.fromString(s)))
|
||||||
|
|
||||||
implicit def mapSatsPerKByteByIntReads: Reads[Map[Int, SatoshisPerKiloByte]] =
|
implicit def mapSatsPerKByteByIntReads: Reads[Map[Int, SatoshisPerKiloByte]] =
|
||||||
Reads.mapReads[Int, SatoshisPerKiloByte](s => JsSuccess(s.toInt))
|
Reads.mapReads[Int, SatoshisPerKiloByte](s => JsSuccess(s.toInt))
|
||||||
|
|
||||||
implicit def mapBitcoinerLiveEstimateReads: Reads[
|
implicit def mapBitcoinerLiveEstimateReads
|
||||||
Map[Int, BitcoinerLiveEstimate]] =
|
: Reads[Map[Int, BitcoinerLiveEstimate]] =
|
||||||
Reads.mapReads[Int, BitcoinerLiveEstimate](s => JsSuccess(s.toInt))
|
Reads.mapReads[Int, BitcoinerLiveEstimate](s => JsSuccess(s.toInt))
|
||||||
|
|
||||||
implicit val outputMapWrites: Writes[Map[BitcoinAddress, Bitcoins]] =
|
implicit val outputMapWrites: Writes[Map[BitcoinAddress, Bitcoins]] =
|
||||||
|
@ -40,7 +40,8 @@ object JsonWriters {
|
|||||||
case _: SIGHASH_SINGLE_ANYONECANPAY => JsString("SINGLE|ANYONECANPAY")
|
case _: SIGHASH_SINGLE_ANYONECANPAY => JsString("SINGLE|ANYONECANPAY")
|
||||||
case _: SIGHASH_ANYONECANPAY =>
|
case _: SIGHASH_ANYONECANPAY =>
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"SIGHHASH_ANYONECANPAY is not supported by the bitcoind RPC interface")
|
"SIGHHASH_ANYONECANPAY is not supported by the bitcoind RPC interface"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,17 +123,22 @@ object JsonWriters {
|
|||||||
|
|
||||||
override def writes(o: TransactionInput): JsValue =
|
override def writes(o: TransactionInput): JsValue =
|
||||||
JsObject(
|
JsObject(
|
||||||
Seq(("txid", JsString(o.previousOutput.txIdBE.hex)),
|
Seq(
|
||||||
("vout", JsNumber(o.previousOutput.vout.toLong)),
|
("txid", JsString(o.previousOutput.txIdBE.hex)),
|
||||||
("sequence", JsNumber(o.sequence.toLong))))
|
("vout", JsNumber(o.previousOutput.vout.toLong)),
|
||||||
|
("sequence", JsNumber(o.sequence.toLong))
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object TransactionOutPointWrites
|
implicit object TransactionOutPointWrites
|
||||||
extends OWrites[TransactionOutPoint] {
|
extends OWrites[TransactionOutPoint] {
|
||||||
|
|
||||||
override def writes(o: TransactionOutPoint): JsObject = {
|
override def writes(o: TransactionOutPoint): JsObject = {
|
||||||
Json.obj(PicklerKeys.txIdKey -> o.txIdBE.hex,
|
Json.obj(
|
||||||
PicklerKeys.voutKey -> o.vout.toLong)
|
PicklerKeys.txIdKey -> o.txIdBE.hex,
|
||||||
|
PicklerKeys.voutKey -> o.vout.toLong
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,8 +158,9 @@ object JsonWriters {
|
|||||||
override def writes(o: PSBT): JsValue = JsString(o.base64)
|
override def writes(o: PSBT): JsValue = JsString(o.base64)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit def mapWrites[K, V](keyString: K => String)(implicit
|
implicit def mapWrites[K, V](
|
||||||
vWrites: Writes[V]): Writes[Map[K, V]] =
|
keyString: K => String
|
||||||
|
)(implicit vWrites: Writes[V]): Writes[Map[K, V]] =
|
||||||
new Writes[Map[K, V]] {
|
new Writes[Map[K, V]] {
|
||||||
|
|
||||||
override def writes(o: Map[K, V]): JsValue =
|
override def writes(o: Map[K, V]): JsValue =
|
||||||
@ -180,7 +187,8 @@ object JsonWriters {
|
|||||||
implicit object LnInvoiceWrites extends Writes[LnInvoice] {
|
implicit object LnInvoiceWrites extends Writes[LnInvoice] {
|
||||||
|
|
||||||
override def writes(invoice: LnInvoice): JsValue = JsString(
|
override def writes(invoice: LnInvoice): JsValue = JsString(
|
||||||
invoice.toString)
|
invoice.toString
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object WalletCreateFundedPsbtOptionsWrites
|
implicit object WalletCreateFundedPsbtOptionsWrites
|
||||||
@ -195,7 +203,8 @@ object JsonWriters {
|
|||||||
)
|
)
|
||||||
|
|
||||||
def addToMapIfDefined[T](key: String, opt: Option[T])(implicit
|
def addToMapIfDefined[T](key: String, opt: Option[T])(implicit
|
||||||
writes: Writes[T]): Unit =
|
writes: Writes[T]
|
||||||
|
): Unit =
|
||||||
opt.foreach(o => jsOpts += (key -> Json.toJson(o)))
|
opt.foreach(o => jsOpts += (key -> Json.toJson(o)))
|
||||||
|
|
||||||
addToMapIfDefined("changeAddress", opts.changeAddress)
|
addToMapIfDefined("changeAddress", opts.changeAddress)
|
||||||
@ -214,7 +223,8 @@ object JsonWriters {
|
|||||||
|
|
||||||
override def writes(o: GlobalPSBTRecord.Unknown): JsValue =
|
override def writes(o: GlobalPSBTRecord.Unknown): JsValue =
|
||||||
JsObject(
|
JsObject(
|
||||||
Seq(("key", JsString(o.key.toHex)), ("value", JsString(o.value.toHex))))
|
Seq(("key", JsString(o.key.toHex)), ("value", JsString(o.value.toHex)))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object InputPSBTRecordUnknownWrites
|
implicit object InputPSBTRecordUnknownWrites
|
||||||
@ -222,7 +232,8 @@ object JsonWriters {
|
|||||||
|
|
||||||
override def writes(o: InputPSBTRecord.Unknown): JsValue =
|
override def writes(o: InputPSBTRecord.Unknown): JsValue =
|
||||||
JsObject(
|
JsObject(
|
||||||
Seq(("key", JsString(o.key.toHex)), ("value", JsString(o.value.toHex))))
|
Seq(("key", JsString(o.key.toHex)), ("value", JsString(o.value.toHex)))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object OutputPSBTRecordUnknownWrites
|
implicit object OutputPSBTRecordUnknownWrites
|
||||||
@ -230,7 +241,8 @@ object JsonWriters {
|
|||||||
|
|
||||||
override def writes(o: OutputPSBTRecord.Unknown): JsValue =
|
override def writes(o: OutputPSBTRecord.Unknown): JsValue =
|
||||||
JsObject(
|
JsObject(
|
||||||
Seq(("key", JsString(o.key.toHex)), ("value", JsString(o.value.toHex))))
|
Seq(("key", JsString(o.key.toHex)), ("value", JsString(o.value.toHex)))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object PartialSignatureWrites
|
implicit object PartialSignatureWrites
|
||||||
@ -238,8 +250,11 @@ object JsonWriters {
|
|||||||
|
|
||||||
override def writes(o: InputPSBTRecord.PartialSignature): JsValue =
|
override def writes(o: InputPSBTRecord.PartialSignature): JsValue =
|
||||||
JsObject(
|
JsObject(
|
||||||
Seq(("pubkey", JsString(o.pubKey.hex)),
|
Seq(
|
||||||
("signature", JsString(o.signature.hex))))
|
("pubkey", JsString(o.pubKey.hex)),
|
||||||
|
("signature", JsString(o.signature.hex))
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object InputBIP32PathWrites
|
implicit object InputBIP32PathWrites
|
||||||
@ -247,9 +262,12 @@ object JsonWriters {
|
|||||||
|
|
||||||
override def writes(o: InputPSBTRecord.BIP32DerivationPath): JsValue =
|
override def writes(o: InputPSBTRecord.BIP32DerivationPath): JsValue =
|
||||||
JsObject(
|
JsObject(
|
||||||
Seq(("pubkey", JsString(o.pubKey.hex)),
|
Seq(
|
||||||
("master_fingerprint", JsString(o.masterFingerprint.toHex)),
|
("pubkey", JsString(o.pubKey.hex)),
|
||||||
("path", JsString(o.path.toString))))
|
("master_fingerprint", JsString(o.masterFingerprint.toHex)),
|
||||||
|
("path", JsString(o.path.toString))
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit object OutputBIP32PathWrites
|
implicit object OutputBIP32PathWrites
|
||||||
@ -257,8 +275,11 @@ object JsonWriters {
|
|||||||
|
|
||||||
override def writes(o: OutputPSBTRecord.BIP32DerivationPath): JsValue =
|
override def writes(o: OutputPSBTRecord.BIP32DerivationPath): JsValue =
|
||||||
JsObject(
|
JsObject(
|
||||||
Seq(("pubkey", JsString(o.pubKey.hex)),
|
Seq(
|
||||||
("master_fingerprint", JsString(o.masterFingerprint.toHex)),
|
("pubkey", JsString(o.pubKey.hex)),
|
||||||
("path", JsString(o.path.toString))))
|
("master_fingerprint", JsString(o.masterFingerprint.toHex)),
|
||||||
|
("path", JsString(o.path.toString))
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,8 @@ object Picklers {
|
|||||||
str => {
|
str => {
|
||||||
val uri = new URI("tcp://" + str)
|
val uri = new URI("tcp://" + str)
|
||||||
InetSocketAddress.createUnresolved(uri.getHost, uri.getPort)
|
InetSocketAddress.createUnresolved(uri.getHost, uri.getPort)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
implicit val byteVectorPickler: ReadWriter[ByteVector] =
|
implicit val byteVectorPickler: ReadWriter[ByteVector] =
|
||||||
readwriter[String].bimap(_.toHex, str => ByteVector.fromValidHex(str))
|
readwriter[String].bimap(_.toHex, str => ByteVector.fromValidHex(str))
|
||||||
@ -80,14 +81,16 @@ object Picklers {
|
|||||||
implicit val schnorrNoncePickler: ReadWriter[SchnorrNonce] =
|
implicit val schnorrNoncePickler: ReadWriter[SchnorrNonce] =
|
||||||
readwriter[String].bimap(_.hex, SchnorrNonce.fromHex)
|
readwriter[String].bimap(_.hex, SchnorrNonce.fromHex)
|
||||||
|
|
||||||
implicit val enumEventDescriptorPickler: ReadWriter[
|
implicit val enumEventDescriptorPickler
|
||||||
EnumEventDescriptorV0TLV] =
|
: ReadWriter[EnumEventDescriptorV0TLV] =
|
||||||
readwriter[String].bimap(_.hex, EnumEventDescriptorV0TLV.fromHex)
|
readwriter[String].bimap(_.hex, EnumEventDescriptorV0TLV.fromHex)
|
||||||
|
|
||||||
implicit val digitDecompEventDescriptorPickler: ReadWriter[
|
implicit val digitDecompEventDescriptorPickler
|
||||||
DigitDecompositionEventDescriptorV0TLV] =
|
: ReadWriter[DigitDecompositionEventDescriptorV0TLV] =
|
||||||
readwriter[String].bimap(_.hex,
|
readwriter[String].bimap(
|
||||||
DigitDecompositionEventDescriptorV0TLV.fromHex)
|
_.hex,
|
||||||
|
DigitDecompositionEventDescriptorV0TLV.fromHex
|
||||||
|
)
|
||||||
|
|
||||||
implicit val eventDescriptorPickler: ReadWriter[EventDescriptorTLV] =
|
implicit val eventDescriptorPickler: ReadWriter[EventDescriptorTLV] =
|
||||||
readwriter[String].bimap(_.hex, EventDescriptorTLV.fromHex)
|
readwriter[String].bimap(_.hex, EventDescriptorTLV.fromHex)
|
||||||
@ -116,8 +119,8 @@ object Picklers {
|
|||||||
implicit val uInt32Pickler: ReadWriter[UInt32] =
|
implicit val uInt32Pickler: ReadWriter[UInt32] =
|
||||||
readwriter[Long].bimap(_.toLong, long => UInt32(long))
|
readwriter[Long].bimap(_.toLong, long => UInt32(long))
|
||||||
|
|
||||||
implicit val satoshisPerVirtualBytePickler: ReadWriter[
|
implicit val satoshisPerVirtualBytePickler
|
||||||
SatoshisPerVirtualByte] =
|
: ReadWriter[SatoshisPerVirtualByte] =
|
||||||
readwriter[Long]
|
readwriter[Long]
|
||||||
.bimap(_.toLong, long => SatoshisPerVirtualByte(Satoshis(long)))
|
.bimap(_.toLong, long => SatoshisPerVirtualByte(Satoshis(long)))
|
||||||
|
|
||||||
@ -133,8 +136,8 @@ object Picklers {
|
|||||||
implicit val contractInfoTLVPickler: ReadWriter[ContractInfoV0TLV] =
|
implicit val contractInfoTLVPickler: ReadWriter[ContractInfoV0TLV] =
|
||||||
readwriter[String].bimap(_.hex, ContractInfoV0TLV.fromHex)
|
readwriter[String].bimap(_.hex, ContractInfoV0TLV.fromHex)
|
||||||
|
|
||||||
implicit val schnorrDigitalSignaturePickler: ReadWriter[
|
implicit val schnorrDigitalSignaturePickler
|
||||||
SchnorrDigitalSignature] =
|
: ReadWriter[SchnorrDigitalSignature] =
|
||||||
readwriter[String].bimap(_.hex, SchnorrDigitalSignature.fromHex)
|
readwriter[String].bimap(_.hex, SchnorrDigitalSignature.fromHex)
|
||||||
|
|
||||||
implicit val partialSignaturePickler: ReadWriter[PartialSignature] =
|
implicit val partialSignaturePickler: ReadWriter[PartialSignature] =
|
||||||
@ -223,14 +226,16 @@ object Picklers {
|
|||||||
upickle.default.read[TransactionOutput](obj(PicklerKeys.outputKey))
|
upickle.default.read[TransactionOutput](obj(PicklerKeys.outputKey))
|
||||||
val hdPath = upickle.default.read[HDPath](obj(PicklerKeys.hdPathKey))
|
val hdPath = upickle.default.read[HDPath](obj(PicklerKeys.hdPathKey))
|
||||||
val redeemScript = upickle.default.read[Option[ScriptPubKey]](
|
val redeemScript = upickle.default.read[Option[ScriptPubKey]](
|
||||||
obj(PicklerKeys.redeemScriptKey))
|
obj(PicklerKeys.redeemScriptKey)
|
||||||
|
)
|
||||||
val scriptWitness =
|
val scriptWitness =
|
||||||
upickle.default.read[Option[ScriptWitness]](obj(PicklerKeys.witnessKey))
|
upickle.default.read[Option[ScriptWitness]](obj(PicklerKeys.witnessKey))
|
||||||
val state = upickle.default.read[TxoState](obj(PicklerKeys.stateKey))
|
val state = upickle.default.read[TxoState](obj(PicklerKeys.stateKey))
|
||||||
val txId =
|
val txId =
|
||||||
upickle.default.read[DoubleSha256DigestBE](obj(PicklerKeys.txIdKey))
|
upickle.default.read[DoubleSha256DigestBE](obj(PicklerKeys.txIdKey))
|
||||||
val spendingTxId = upickle.default.read[Option[DoubleSha256DigestBE]](
|
val spendingTxId = upickle.default.read[Option[DoubleSha256DigestBE]](
|
||||||
obj(PicklerKeys.spendingTxIdKey))
|
obj(PicklerKeys.spendingTxIdKey)
|
||||||
|
)
|
||||||
SpendingInfoDb(
|
SpendingInfoDb(
|
||||||
id = id,
|
id = id,
|
||||||
outpoint = outpoint,
|
outpoint = outpoint,
|
||||||
@ -293,7 +298,8 @@ object Picklers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def parseAdaptorSignatures(
|
private def parseAdaptorSignatures(
|
||||||
arr: ujson.Arr): Vector[ECAdaptorSignature] = {
|
arr: ujson.Arr
|
||||||
|
): Vector[ECAdaptorSignature] = {
|
||||||
arr.value.toVector.map {
|
arr.value.toVector.map {
|
||||||
case obj: ujson.Obj =>
|
case obj: ujson.Obj =>
|
||||||
ECAdaptorSignature.fromHex(obj(PicklerKeys.signatureKey).str)
|
ECAdaptorSignature.fromHex(obj(PicklerKeys.signatureKey).str)
|
||||||
@ -303,19 +309,22 @@ object Picklers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def writeAdaptorSignatures(
|
private def writeAdaptorSignatures(
|
||||||
sigs: Vector[ECAdaptorSignature]): Vector[ujson.Obj] = {
|
sigs: Vector[ECAdaptorSignature]
|
||||||
|
): Vector[ujson.Obj] = {
|
||||||
sigs.map { sig =>
|
sigs.map { sig =>
|
||||||
ujson.Obj(PicklerKeys.signatureKey -> Str(sig.hex))
|
ujson.Obj(PicklerKeys.signatureKey -> Str(sig.hex))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def writeCetAdaptorSigs(
|
private def writeCetAdaptorSigs(
|
||||||
cetSignaturesTLV: CETSignaturesTLV): ujson.Obj = {
|
cetSignaturesTLV: CETSignaturesTLV
|
||||||
|
): ujson.Obj = {
|
||||||
cetSignaturesTLV match {
|
cetSignaturesTLV match {
|
||||||
case v0: CETSignaturesV0TLV =>
|
case v0: CETSignaturesV0TLV =>
|
||||||
val sigsVec = writeAdaptorSignatures(v0.sigs)
|
val sigsVec = writeAdaptorSignatures(v0.sigs)
|
||||||
ujson.Obj(
|
ujson.Obj(
|
||||||
PicklerKeys.ecdsaAdaptorSignaturesKey -> ujson.Arr.from(sigsVec))
|
PicklerKeys.ecdsaAdaptorSignaturesKey -> ujson.Arr.from(sigsVec)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,17 +332,20 @@ object Picklers {
|
|||||||
val tempContractId =
|
val tempContractId =
|
||||||
Sha256Digest.fromHex(obj(PicklerKeys.tempContractIdKey).str)
|
Sha256Digest.fromHex(obj(PicklerKeys.tempContractIdKey).str)
|
||||||
val acceptCollateral = Satoshis(
|
val acceptCollateral = Satoshis(
|
||||||
obj(PicklerKeys.acceptCollateralKey).num.toLong)
|
obj(PicklerKeys.acceptCollateralKey).num.toLong
|
||||||
|
)
|
||||||
val fundingPubKey =
|
val fundingPubKey =
|
||||||
ECPublicKey.fromHex(obj(PicklerKeys.fundingPubKeyKey).str)
|
ECPublicKey.fromHex(obj(PicklerKeys.fundingPubKeyKey).str)
|
||||||
val payoutSpk = ScriptPubKey.fromAsmHex(obj(PicklerKeys.payoutSpkKey).str)
|
val payoutSpk = ScriptPubKey.fromAsmHex(obj(PicklerKeys.payoutSpkKey).str)
|
||||||
val payoutSerialId = parseU64(obj(PicklerKeys.payoutSerialIdKey).str)
|
val payoutSerialId = parseU64(obj(PicklerKeys.payoutSerialIdKey).str)
|
||||||
val fundingInputs = parseFundingInputs(
|
val fundingInputs = parseFundingInputs(
|
||||||
obj(PicklerKeys.fundingInputsKey).arr)
|
obj(PicklerKeys.fundingInputsKey).arr
|
||||||
|
)
|
||||||
val changeSpk = ScriptPubKey.fromAsmHex(obj(PicklerKeys.changeSpkKey).str)
|
val changeSpk = ScriptPubKey.fromAsmHex(obj(PicklerKeys.changeSpkKey).str)
|
||||||
val changeSerialId = parseU64(obj(PicklerKeys.changeSerialIdKey).str)
|
val changeSerialId = parseU64(obj(PicklerKeys.changeSerialIdKey).str)
|
||||||
val cetAdaptorSigs = parseCetAdaptorSignatures(
|
val cetAdaptorSigs = parseCetAdaptorSignatures(
|
||||||
obj(PicklerKeys.cetAdaptorSignaturesKey).obj)
|
obj(PicklerKeys.cetAdaptorSignaturesKey).obj
|
||||||
|
)
|
||||||
val refundSignature =
|
val refundSignature =
|
||||||
ECDigitalSignature.fromHex(obj(PicklerKeys.refundSignatureKey).str)
|
ECDigitalSignature.fromHex(obj(PicklerKeys.refundSignatureKey).str)
|
||||||
val negotiationFields = {
|
val negotiationFields = {
|
||||||
@ -365,17 +377,21 @@ object Picklers {
|
|||||||
Obj(
|
Obj(
|
||||||
PicklerKeys.tempContractIdKey -> Str(accept.tempContractId.hex),
|
PicklerKeys.tempContractIdKey -> Str(accept.tempContractId.hex),
|
||||||
PicklerKeys.acceptCollateralKey -> Num(
|
PicklerKeys.acceptCollateralKey -> Num(
|
||||||
accept.acceptCollateralSatoshis.toLong.toDouble),
|
accept.acceptCollateralSatoshis.toLong.toDouble
|
||||||
|
),
|
||||||
PicklerKeys.fundingPubKeyKey -> Str(accept.fundingPubKey.hex),
|
PicklerKeys.fundingPubKeyKey -> Str(accept.fundingPubKey.hex),
|
||||||
PicklerKeys.payoutSpkKey -> Str(accept.payoutSPK.asmHex),
|
PicklerKeys.payoutSpkKey -> Str(accept.payoutSPK.asmHex),
|
||||||
PicklerKeys.payoutSerialIdKey -> Str(
|
PicklerKeys.payoutSerialIdKey -> Str(
|
||||||
accept.payoutSerialId.toBigInt.toString()),
|
accept.payoutSerialId.toBigInt.toString()
|
||||||
|
),
|
||||||
PicklerKeys.fundingInputsKey -> writeJs(accept.fundingInputs),
|
PicklerKeys.fundingInputsKey -> writeJs(accept.fundingInputs),
|
||||||
PicklerKeys.changeSpkKey -> Str(accept.changeSPK.asmHex),
|
PicklerKeys.changeSpkKey -> Str(accept.changeSPK.asmHex),
|
||||||
PicklerKeys.changeSerialIdKey -> Str(
|
PicklerKeys.changeSerialIdKey -> Str(
|
||||||
accept.changeSerialId.toBigInt.toString()),
|
accept.changeSerialId.toBigInt.toString()
|
||||||
|
),
|
||||||
PicklerKeys.cetAdaptorSignaturesKey -> writeCetAdaptorSigs(
|
PicklerKeys.cetAdaptorSignaturesKey -> writeCetAdaptorSigs(
|
||||||
accept.cetSignatures),
|
accept.cetSignatures
|
||||||
|
),
|
||||||
PicklerKeys.refundSignatureKey -> Str(accept.refundSignature.hex),
|
PicklerKeys.refundSignatureKey -> Str(accept.refundSignature.hex),
|
||||||
PicklerKeys.negotiationFieldsKey -> ujson.Null
|
PicklerKeys.negotiationFieldsKey -> ujson.Null
|
||||||
)
|
)
|
||||||
@ -383,13 +399,15 @@ object Picklers {
|
|||||||
|
|
||||||
private def parseFundingSignatures(obj: ujson.Obj): FundingSignaturesTLV = {
|
private def parseFundingSignatures(obj: ujson.Obj): FundingSignaturesTLV = {
|
||||||
val fundingSignatures: Vector[ujson.Value] = obj(
|
val fundingSignatures: Vector[ujson.Value] = obj(
|
||||||
PicklerKeys.fundingSignaturesKey).arr.toVector
|
PicklerKeys.fundingSignaturesKey
|
||||||
|
).arr.toVector
|
||||||
val witV0 = paresFundingSignaturesArr(fundingSignatures)
|
val witV0 = paresFundingSignaturesArr(fundingSignatures)
|
||||||
FundingSignaturesV0TLV(witV0)
|
FundingSignaturesV0TLV(witV0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def paresFundingSignaturesArr(
|
private def paresFundingSignaturesArr(
|
||||||
arr: Vector[ujson.Value]): Vector[ScriptWitnessV0] = {
|
arr: Vector[ujson.Value]
|
||||||
|
): Vector[ScriptWitnessV0] = {
|
||||||
arr.map {
|
arr.map {
|
||||||
case obj: ujson.Obj =>
|
case obj: ujson.Obj =>
|
||||||
val witnessElementsArr = obj(PicklerKeys.witnessElementsKey).arr
|
val witnessElementsArr = obj(PicklerKeys.witnessElementsKey).arr
|
||||||
@ -405,7 +423,8 @@ object Picklers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def writeFundingSignatures(
|
private def writeFundingSignatures(
|
||||||
fundingSigs: FundingSignaturesTLV): ujson.Obj = {
|
fundingSigs: FundingSignaturesTLV
|
||||||
|
): ujson.Obj = {
|
||||||
val sigs: Vector[ujson.Obj] = fundingSigs match {
|
val sigs: Vector[ujson.Obj] = fundingSigs match {
|
||||||
case v0: FundingSignaturesV0TLV =>
|
case v0: FundingSignaturesV0TLV =>
|
||||||
val witnessJson: Vector[Obj] = {
|
val witnessJson: Vector[Obj] = {
|
||||||
@ -424,11 +443,13 @@ object Picklers {
|
|||||||
private def readSignTLV(obj: ujson.Obj): DLCSignTLV = {
|
private def readSignTLV(obj: ujson.Obj): DLCSignTLV = {
|
||||||
val contractId = ByteVector.fromValidHex(obj(PicklerKeys.contractIdKey).str)
|
val contractId = ByteVector.fromValidHex(obj(PicklerKeys.contractIdKey).str)
|
||||||
val adaptorSigs = parseCetAdaptorSignatures(
|
val adaptorSigs = parseCetAdaptorSignatures(
|
||||||
obj(PicklerKeys.cetAdaptorSignaturesKey).obj)
|
obj(PicklerKeys.cetAdaptorSignaturesKey).obj
|
||||||
|
)
|
||||||
val refundSignature =
|
val refundSignature =
|
||||||
ECDigitalSignature.fromHex(obj(PicklerKeys.refundSignatureKey).str)
|
ECDigitalSignature.fromHex(obj(PicklerKeys.refundSignatureKey).str)
|
||||||
val fundingSignatures = parseFundingSignatures(
|
val fundingSignatures = parseFundingSignatures(
|
||||||
obj(PicklerKeys.fundingSignaturesKey).obj)
|
obj(PicklerKeys.fundingSignaturesKey).obj
|
||||||
|
)
|
||||||
|
|
||||||
val signTLV =
|
val signTLV =
|
||||||
DLCSignTLV(contractId, adaptorSigs, refundSignature, fundingSignatures)
|
DLCSignTLV(contractId, adaptorSigs, refundSignature, fundingSignatures)
|
||||||
@ -441,7 +462,8 @@ object Picklers {
|
|||||||
ujson.Obj(
|
ujson.Obj(
|
||||||
PicklerKeys.contractIdKey -> sign.contractId.toHex,
|
PicklerKeys.contractIdKey -> sign.contractId.toHex,
|
||||||
PicklerKeys.cetAdaptorSignaturesKey -> writeCetAdaptorSigs(
|
PicklerKeys.cetAdaptorSignaturesKey -> writeCetAdaptorSigs(
|
||||||
sign.cetSignatures),
|
sign.cetSignatures
|
||||||
|
),
|
||||||
PicklerKeys.refundSignatureKey -> ujson.Str(sign.refundSignature.hex),
|
PicklerKeys.refundSignatureKey -> ujson.Str(sign.refundSignature.hex),
|
||||||
PicklerKeys.fundingSignaturesKey ->
|
PicklerKeys.fundingSignaturesKey ->
|
||||||
writeFundingSignatures(sign.fundingSignatures)
|
writeFundingSignatures(sign.fundingSignatures)
|
||||||
@ -456,8 +478,8 @@ object Picklers {
|
|||||||
readwriter[ujson.Obj].bimap(writeSignTLV, readSignTLV)
|
readwriter[ujson.Obj].bimap(writeSignTLV, readSignTLV)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val lnMessageDLCAcceptTLVPickler: ReadWriter[
|
implicit val lnMessageDLCAcceptTLVPickler
|
||||||
LnMessage[DLCAcceptTLV]] =
|
: ReadWriter[LnMessage[DLCAcceptTLV]] =
|
||||||
readwriter[String].bimap(_.hex, LnMessageFactory(DLCAcceptTLV).fromHex)
|
readwriter[String].bimap(_.hex, LnMessageFactory(DLCAcceptTLV).fromHex)
|
||||||
|
|
||||||
implicit val lnMessageDLCSignTLVPickler: ReadWriter[LnMessage[DLCSignTLV]] =
|
implicit val lnMessageDLCSignTLVPickler: ReadWriter[LnMessage[DLCSignTLV]] =
|
||||||
@ -488,8 +510,8 @@ object Picklers {
|
|||||||
implicit val addressLabelTagPickler: ReadWriter[AddressLabelTag] =
|
implicit val addressLabelTagPickler: ReadWriter[AddressLabelTag] =
|
||||||
readwriter[String].bimap(_.name, AddressLabelTag)
|
readwriter[String].bimap(_.name, AddressLabelTag)
|
||||||
|
|
||||||
implicit val lockUnspentOutputParameterPickler: ReadWriter[
|
implicit val lockUnspentOutputParameterPickler
|
||||||
LockUnspentOutputParameter] =
|
: ReadWriter[LockUnspentOutputParameter] =
|
||||||
readwriter[Value].bimap(_.toJson, LockUnspentOutputParameter.fromJson)
|
readwriter[Value].bimap(_.toJson, LockUnspentOutputParameter.fromJson)
|
||||||
|
|
||||||
// can't make implicit because it will overlap with ones needed for cli
|
// can't make implicit because it will overlap with ones needed for cli
|
||||||
@ -501,8 +523,10 @@ object Picklers {
|
|||||||
|
|
||||||
val descriptorJson = announcement.eventTLV.eventDescriptor match {
|
val descriptorJson = announcement.eventTLV.eventDescriptor match {
|
||||||
case EnumEventDescriptorV0TLV(outcomes) =>
|
case EnumEventDescriptorV0TLV(outcomes) =>
|
||||||
Obj("outcomes" -> outcomes.map(Str(_)),
|
Obj(
|
||||||
"hex" -> announcement.eventTLV.eventDescriptor.hex)
|
"outcomes" -> outcomes.map(Str(_)),
|
||||||
|
"hex" -> announcement.eventTLV.eventDescriptor.hex
|
||||||
|
)
|
||||||
case numeric: NumericEventDescriptorTLV =>
|
case numeric: NumericEventDescriptorTLV =>
|
||||||
Obj(
|
Obj(
|
||||||
"base" -> Num(numeric.base.toLong.toDouble),
|
"base" -> Num(numeric.base.toLong.toDouble),
|
||||||
@ -516,10 +540,12 @@ object Picklers {
|
|||||||
val maturityStr =
|
val maturityStr =
|
||||||
TimeUtil.iso8601ToString(Date.from(announcement.eventTLV.maturation))
|
TimeUtil.iso8601ToString(Date.from(announcement.eventTLV.maturation))
|
||||||
|
|
||||||
val eventJson = Obj("nonces" -> noncesJson,
|
val eventJson = Obj(
|
||||||
"maturity" -> Str(maturityStr),
|
"nonces" -> noncesJson,
|
||||||
"descriptor" -> descriptorJson,
|
"maturity" -> Str(maturityStr),
|
||||||
"eventId" -> Str(announcement.eventTLV.eventId))
|
"descriptor" -> descriptorJson,
|
||||||
|
"eventId" -> Str(announcement.eventTLV.eventId)
|
||||||
|
)
|
||||||
|
|
||||||
Obj(
|
Obj(
|
||||||
"announcementSignature" -> Str(announcement.announcementSignature.hex),
|
"announcementSignature" -> Str(announcement.announcementSignature.hex),
|
||||||
@ -541,10 +567,12 @@ object Picklers {
|
|||||||
val sigsJson = attestments.sigs.map(sig => Str(sig.hex))
|
val sigsJson = attestments.sigs.map(sig => Str(sig.hex))
|
||||||
val valuesJson = attestments.outcomes.map(Str(_))
|
val valuesJson = attestments.outcomes.map(Str(_))
|
||||||
|
|
||||||
Obj("eventId" -> Str(attestments.eventId),
|
Obj(
|
||||||
"signatures" -> sigsJson,
|
"eventId" -> Str(attestments.eventId),
|
||||||
"values" -> valuesJson,
|
"signatures" -> sigsJson,
|
||||||
"hex" -> attestments.hex)
|
"values" -> valuesJson,
|
||||||
|
"hex" -> attestments.hex
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val fundingInputV0Writer: Writer[FundingInputTLV] =
|
implicit val fundingInputV0Writer: Writer[FundingInputTLV] =
|
||||||
@ -591,15 +619,17 @@ object Picklers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val hyperbolaPayoutCurvePieceTLVWriter: Writer[
|
implicit val hyperbolaPayoutCurvePieceTLVWriter
|
||||||
HyperbolaPayoutCurvePieceTLV] = {
|
: Writer[HyperbolaPayoutCurvePieceTLV] = {
|
||||||
writer[Obj].comap { piece =>
|
writer[Obj].comap { piece =>
|
||||||
Obj(
|
Obj(
|
||||||
PicklerKeys.usePositivePiece -> Bool(piece.usePositivePiece),
|
PicklerKeys.usePositivePiece -> Bool(piece.usePositivePiece),
|
||||||
PicklerKeys.translateOutcome -> Num(
|
PicklerKeys.translateOutcome -> Num(
|
||||||
piece.translateOutcome.toBigDecimal.toDouble),
|
piece.translateOutcome.toBigDecimal.toDouble
|
||||||
|
),
|
||||||
PicklerKeys.translatePayout -> Num(
|
PicklerKeys.translatePayout -> Num(
|
||||||
piece.translatePayout.toBigDecimal.toDouble),
|
piece.translatePayout.toBigDecimal.toDouble
|
||||||
|
),
|
||||||
PicklerKeys.a -> Num(piece.a.toBigDecimal.toDouble),
|
PicklerKeys.a -> Num(piece.a.toBigDecimal.toDouble),
|
||||||
PicklerKeys.b -> Num(piece.b.toBigDecimal.toDouble),
|
PicklerKeys.b -> Num(piece.b.toBigDecimal.toDouble),
|
||||||
PicklerKeys.c -> Num(piece.c.toBigDecimal.toDouble),
|
PicklerKeys.c -> Num(piece.c.toBigDecimal.toDouble),
|
||||||
@ -612,7 +642,7 @@ object Picklers {
|
|||||||
implicit val payoutFunctionV0TLVWriter: Writer[PayoutFunctionV0TLV] = {
|
implicit val payoutFunctionV0TLVWriter: Writer[PayoutFunctionV0TLV] = {
|
||||||
def endpoint(json: Value, isEndpoint: Boolean): Value = json match {
|
def endpoint(json: Value, isEndpoint: Boolean): Value = json match {
|
||||||
case obj: Obj =>
|
case obj: Obj =>
|
||||||
//drop old value on the floor if there is one
|
// drop old value on the floor if there is one
|
||||||
obj.value.put(PicklerKeys.isEndpointKey, Bool(isEndpoint))
|
obj.value.put(PicklerKeys.isEndpointKey, Bool(isEndpoint))
|
||||||
Obj(obj.value)
|
Obj(obj.value)
|
||||||
case v: Value => v
|
case v: Value => v
|
||||||
@ -644,7 +674,8 @@ object Picklers {
|
|||||||
val points: Vector[TLVPoint] = pointsArr.map {
|
val points: Vector[TLVPoint] = pointsArr.map {
|
||||||
case x @ (_: Arr | _: Num | Null | _: Bool | _: Str) =>
|
case x @ (_: Arr | _: Num | Null | _: Bool | _: Str) =>
|
||||||
sys.error(
|
sys.error(
|
||||||
s"Cannot have $x when parsing payout curve points, expected json object")
|
s"Cannot have $x when parsing payout curve points, expected json object"
|
||||||
|
)
|
||||||
case obj: Obj =>
|
case obj: Obj =>
|
||||||
upickle.default.read[TLVPoint](obj)
|
upickle.default.read[TLVPoint](obj)
|
||||||
}.toVector
|
}.toVector
|
||||||
@ -660,8 +691,10 @@ object Picklers {
|
|||||||
import roundingIntervals._
|
import roundingIntervals._
|
||||||
|
|
||||||
val intervalsJs = intervalStarts.map { i =>
|
val intervalsJs = intervalStarts.map { i =>
|
||||||
Obj("beginInterval" -> Num(i._1.toDouble),
|
Obj(
|
||||||
"roundingMod" -> Num(i._2.toLong.toDouble))
|
"beginInterval" -> Num(i._1.toDouble),
|
||||||
|
"roundingMod" -> Num(i._2.toLong.toDouble)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Obj("intervals" -> intervalsJs)
|
Obj("intervals" -> intervalsJs)
|
||||||
@ -686,10 +719,12 @@ object Picklers {
|
|||||||
writer[Obj].comap { v1 =>
|
writer[Obj].comap { v1 =>
|
||||||
import v1._
|
import v1._
|
||||||
|
|
||||||
Obj("numDigits" -> Num(numDigits.toDouble),
|
Obj(
|
||||||
"payoutFunction" -> writeJs(payoutFunction),
|
"numDigits" -> Num(numDigits.toDouble),
|
||||||
"roundingIntervals" -> writeJs(roundingIntervals),
|
"payoutFunction" -> writeJs(payoutFunction),
|
||||||
"hex" -> v1.hex)
|
"roundingIntervals" -> writeJs(roundingIntervals),
|
||||||
|
"hex" -> v1.hex
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val contractDescriptorWriter: Writer[ContractDescriptorTLV] =
|
implicit val contractDescriptorWriter: Writer[ContractDescriptorTLV] =
|
||||||
@ -704,23 +739,29 @@ object Picklers {
|
|||||||
writer[Obj].comap { oracleInfo =>
|
writer[Obj].comap { oracleInfo =>
|
||||||
Obj(
|
Obj(
|
||||||
"announcement" -> writeJs(oracleInfo.announcement)(
|
"announcement" -> writeJs(oracleInfo.announcement)(
|
||||||
oracleAnnouncementTLVJsonWriter))
|
oracleAnnouncementTLVJsonWriter
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val oracleInfoV1TLVWriter: Writer[OracleInfoV1TLV] =
|
implicit val oracleInfoV1TLVWriter: Writer[OracleInfoV1TLV] =
|
||||||
writer[Obj].comap { oracleInfo =>
|
writer[Obj].comap { oracleInfo =>
|
||||||
import oracleInfo._
|
import oracleInfo._
|
||||||
Obj("threshold" -> Num(threshold.toDouble),
|
Obj(
|
||||||
"announcements" -> oracles.map(o =>
|
"threshold" -> Num(threshold.toDouble),
|
||||||
writeJs(o)(oracleAnnouncementTLVJsonWriter)))
|
"announcements" -> oracles.map(o =>
|
||||||
|
writeJs(o)(oracleAnnouncementTLVJsonWriter))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val oracleParamsV0TLVWriter: Writer[OracleParamsV0TLV] =
|
implicit val oracleParamsV0TLVWriter: Writer[OracleParamsV0TLV] =
|
||||||
writer[Obj].comap { params =>
|
writer[Obj].comap { params =>
|
||||||
import params._
|
import params._
|
||||||
Obj("maxErrorExp" -> Num(maxErrorExp.toDouble),
|
Obj(
|
||||||
"minFailExp" -> Num(minFailExp.toDouble),
|
"maxErrorExp" -> Num(maxErrorExp.toDouble),
|
||||||
"maximizeCoverage" -> Bool(maximizeCoverage))
|
"minFailExp" -> Num(minFailExp.toDouble),
|
||||||
|
"maximizeCoverage" -> Bool(maximizeCoverage)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val oracleParamsTLVWriter: Writer[OracleParamsTLV] =
|
implicit val oracleParamsTLVWriter: Writer[OracleParamsTLV] =
|
||||||
@ -731,10 +772,12 @@ object Picklers {
|
|||||||
implicit val oracleInfoV2TLVWriter: Writer[OracleInfoV2TLV] =
|
implicit val oracleInfoV2TLVWriter: Writer[OracleInfoV2TLV] =
|
||||||
writer[Obj].comap { oracleInfo =>
|
writer[Obj].comap { oracleInfo =>
|
||||||
import oracleInfo._
|
import oracleInfo._
|
||||||
Obj("threshold" -> Num(threshold.toDouble),
|
Obj(
|
||||||
"announcements" -> oracles.map(o =>
|
"threshold" -> Num(threshold.toDouble),
|
||||||
writeJs(o)(oracleAnnouncementTLVJsonWriter)),
|
"announcements" -> oracles.map(o =>
|
||||||
"params" -> writeJs(params))
|
writeJs(o)(oracleAnnouncementTLVJsonWriter)),
|
||||||
|
"params" -> writeJs(params)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val oracleInfoTLVWriter: Writer[OracleInfoTLV] =
|
implicit val oracleInfoTLVWriter: Writer[OracleInfoTLV] =
|
||||||
@ -762,15 +805,18 @@ object Picklers {
|
|||||||
case (c, o) =>
|
case (c, o) =>
|
||||||
val contractDescriptorJson = writeJs(c)
|
val contractDescriptorJson = writeJs(c)
|
||||||
val oracleInfoJson = writeJs(o)
|
val oracleInfoJson = writeJs(o)
|
||||||
ujson.Obj(PicklerKeys.contractDescriptorKey -> contractDescriptorJson,
|
ujson.Obj(
|
||||||
PicklerKeys.oracleInfoKey -> oracleInfoJson)
|
PicklerKeys.contractDescriptorKey -> contractDescriptorJson,
|
||||||
|
PicklerKeys.oracleInfoKey -> oracleInfoJson
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val arrayJson = ujson.Arr.from(arrayVec)
|
val arrayJson = ujson.Arr.from(arrayVec)
|
||||||
|
|
||||||
Obj(
|
Obj(
|
||||||
PicklerKeys.totalCollateralKey -> Num(
|
PicklerKeys.totalCollateralKey -> Num(
|
||||||
contractInfo.totalCollateral.toLong.toDouble),
|
contractInfo.totalCollateral.toLong.toDouble
|
||||||
|
),
|
||||||
PicklerKeys.pairsKey -> arrayJson
|
PicklerKeys.pairsKey -> arrayJson
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -840,9 +886,11 @@ object Picklers {
|
|||||||
PicklerKeys.tempContractIdKey -> Str(tempContractId.hex),
|
PicklerKeys.tempContractIdKey -> Str(tempContractId.hex),
|
||||||
"contractInfo" -> Str(contractInfo.hex),
|
"contractInfo" -> Str(contractInfo.hex),
|
||||||
"contractMaturity" -> Num(
|
"contractMaturity" -> Num(
|
||||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
timeouts.contractMaturity.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"contractTimeout" -> Num(
|
"contractTimeout" -> Num(
|
||||||
timeouts.contractTimeout.toUInt32.toLong.toDouble),
|
timeouts.contractTimeout.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"feeRate" -> Num(feeRate.toLong.toDouble),
|
"feeRate" -> Num(feeRate.toLong.toDouble),
|
||||||
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
||||||
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
||||||
@ -852,8 +900,8 @@ object Picklers {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val acceptedComputingAdaptorSigsW: Writer[
|
implicit val acceptedComputingAdaptorSigsW
|
||||||
AcceptedComputingAdaptorSigs] = writer[Obj].comap { accepted =>
|
: Writer[AcceptedComputingAdaptorSigs] = writer[Obj].comap { accepted =>
|
||||||
import accepted._
|
import accepted._
|
||||||
Obj(
|
Obj(
|
||||||
"state" -> Str(statusString),
|
"state" -> Str(statusString),
|
||||||
@ -864,9 +912,11 @@ object Picklers {
|
|||||||
"contractId" -> Str(contractId.toHex),
|
"contractId" -> Str(contractId.toHex),
|
||||||
"contractInfo" -> Str(contractInfo.hex),
|
"contractInfo" -> Str(contractInfo.hex),
|
||||||
"contractMaturity" -> Num(
|
"contractMaturity" -> Num(
|
||||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
timeouts.contractMaturity.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"contractTimeout" -> Num(
|
"contractTimeout" -> Num(
|
||||||
timeouts.contractTimeout.toUInt32.toLong.toDouble),
|
timeouts.contractTimeout.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"feeRate" -> Num(feeRate.toLong.toDouble),
|
"feeRate" -> Num(feeRate.toLong.toDouble),
|
||||||
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
||||||
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
||||||
@ -887,9 +937,11 @@ object Picklers {
|
|||||||
"contractId" -> Str(contractId.toHex),
|
"contractId" -> Str(contractId.toHex),
|
||||||
"contractInfo" -> Str(contractInfo.hex),
|
"contractInfo" -> Str(contractInfo.hex),
|
||||||
"contractMaturity" -> Num(
|
"contractMaturity" -> Num(
|
||||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
timeouts.contractMaturity.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"contractTimeout" -> Num(
|
"contractTimeout" -> Num(
|
||||||
timeouts.contractTimeout.toUInt32.toLong.toDouble),
|
timeouts.contractTimeout.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"feeRate" -> Num(feeRate.toLong.toDouble),
|
"feeRate" -> Num(feeRate.toLong.toDouble),
|
||||||
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
||||||
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
||||||
@ -911,9 +963,11 @@ object Picklers {
|
|||||||
"contractId" -> Str(contractId.toHex),
|
"contractId" -> Str(contractId.toHex),
|
||||||
"contractInfo" -> Str(contractInfo.hex),
|
"contractInfo" -> Str(contractInfo.hex),
|
||||||
"contractMaturity" -> Num(
|
"contractMaturity" -> Num(
|
||||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
timeouts.contractMaturity.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"contractTimeout" -> Num(
|
"contractTimeout" -> Num(
|
||||||
timeouts.contractTimeout.toUInt32.toLong.toDouble),
|
timeouts.contractTimeout.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"feeRate" -> Num(feeRate.toLong.toDouble),
|
"feeRate" -> Num(feeRate.toLong.toDouble),
|
||||||
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
||||||
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
||||||
@ -935,9 +989,11 @@ object Picklers {
|
|||||||
"contractId" -> Str(contractId.toHex),
|
"contractId" -> Str(contractId.toHex),
|
||||||
"contractInfo" -> Str(contractInfo.hex),
|
"contractInfo" -> Str(contractInfo.hex),
|
||||||
"contractMaturity" -> Num(
|
"contractMaturity" -> Num(
|
||||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
timeouts.contractMaturity.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"contractTimeout" -> Num(
|
"contractTimeout" -> Num(
|
||||||
timeouts.contractTimeout.toUInt32.toLong.toDouble),
|
timeouts.contractTimeout.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"feeRate" -> Num(feeRate.toLong.toDouble),
|
"feeRate" -> Num(feeRate.toLong.toDouble),
|
||||||
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
||||||
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
||||||
@ -960,9 +1016,11 @@ object Picklers {
|
|||||||
"contractId" -> Str(contractId.toHex),
|
"contractId" -> Str(contractId.toHex),
|
||||||
"contractInfo" -> Str(contractInfo.hex),
|
"contractInfo" -> Str(contractInfo.hex),
|
||||||
"contractMaturity" -> Num(
|
"contractMaturity" -> Num(
|
||||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
timeouts.contractMaturity.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"contractTimeout" -> Num(
|
"contractTimeout" -> Num(
|
||||||
timeouts.contractTimeout.toUInt32.toLong.toDouble),
|
timeouts.contractTimeout.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"feeRate" -> Num(feeRate.toLong.toDouble),
|
"feeRate" -> Num(feeRate.toLong.toDouble),
|
||||||
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
||||||
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
||||||
@ -985,9 +1043,11 @@ object Picklers {
|
|||||||
"contractId" -> Str(contractId.toHex),
|
"contractId" -> Str(contractId.toHex),
|
||||||
"contractInfo" -> Str(contractInfo.hex),
|
"contractInfo" -> Str(contractInfo.hex),
|
||||||
"contractMaturity" -> Num(
|
"contractMaturity" -> Num(
|
||||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
timeouts.contractMaturity.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"contractTimeout" -> Num(
|
"contractTimeout" -> Num(
|
||||||
timeouts.contractTimeout.toUInt32.toLong.toDouble),
|
timeouts.contractTimeout.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"feeRate" -> Num(feeRate.toLong.toDouble),
|
"feeRate" -> Num(feeRate.toLong.toDouble),
|
||||||
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
||||||
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
||||||
@ -1004,11 +1064,15 @@ object Picklers {
|
|||||||
import claimed._
|
import claimed._
|
||||||
val (oraclesJs, outcomesJs) = oracleOutcome match {
|
val (oraclesJs, outcomesJs) = oracleOutcome match {
|
||||||
case EnumOracleOutcome(oracles, outcome) =>
|
case EnumOracleOutcome(oracles, outcome) =>
|
||||||
(Arr.from(oracles.map(o => Str(o.announcement.hex))),
|
(
|
||||||
Str(outcome.outcome))
|
Arr.from(oracles.map(o => Str(o.announcement.hex))),
|
||||||
|
Str(outcome.outcome)
|
||||||
|
)
|
||||||
case numeric: NumericOracleOutcome =>
|
case numeric: NumericOracleOutcome =>
|
||||||
(Arr.from(numeric.oracles.map(_.announcement.hex)),
|
(
|
||||||
Arr.from(numeric.outcomes.map(o => Arr.from(o.digits))))
|
Arr.from(numeric.oracles.map(_.announcement.hex)),
|
||||||
|
Arr.from(numeric.outcomes.map(o => Arr.from(o.digits)))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Obj(
|
Obj(
|
||||||
@ -1020,9 +1084,11 @@ object Picklers {
|
|||||||
"contractId" -> Str(contractId.toHex),
|
"contractId" -> Str(contractId.toHex),
|
||||||
"contractInfo" -> Str(contractInfo.hex),
|
"contractInfo" -> Str(contractInfo.hex),
|
||||||
"contractMaturity" -> Num(
|
"contractMaturity" -> Num(
|
||||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
timeouts.contractMaturity.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"contractTimeout" -> Num(
|
"contractTimeout" -> Num(
|
||||||
timeouts.contractTimeout.toUInt32.toLong.toDouble),
|
timeouts.contractTimeout.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"feeRate" -> Num(feeRate.toLong.toDouble),
|
"feeRate" -> Num(feeRate.toLong.toDouble),
|
||||||
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
||||||
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
||||||
@ -1034,7 +1100,8 @@ object Picklers {
|
|||||||
"oracles" -> oraclesJs,
|
"oracles" -> oraclesJs,
|
||||||
PicklerKeys.myPayout -> Num(claimed.myPayout.satoshis.toLong.toDouble),
|
PicklerKeys.myPayout -> Num(claimed.myPayout.satoshis.toLong.toDouble),
|
||||||
counterPartyPayoutKey -> Num(
|
counterPartyPayoutKey -> Num(
|
||||||
claimed.counterPartyPayout.satoshis.toLong.toDouble),
|
claimed.counterPartyPayout.satoshis.toLong.toDouble
|
||||||
|
),
|
||||||
PicklerKeys.pnl -> Num(claimed.pnl.satoshis.toLong.toDouble),
|
PicklerKeys.pnl -> Num(claimed.pnl.satoshis.toLong.toDouble),
|
||||||
PicklerKeys.rateOfReturn -> Num(claimed.rateOfReturn.toDouble),
|
PicklerKeys.rateOfReturn -> Num(claimed.rateOfReturn.toDouble),
|
||||||
"payoutAddress" -> writeJs(payoutAddress),
|
"payoutAddress" -> writeJs(payoutAddress),
|
||||||
@ -1047,11 +1114,15 @@ object Picklers {
|
|||||||
import remoteClaimed._
|
import remoteClaimed._
|
||||||
val (oraclesJs, outcomesJs) = oracleOutcome match {
|
val (oraclesJs, outcomesJs) = oracleOutcome match {
|
||||||
case EnumOracleOutcome(oracles, outcome) =>
|
case EnumOracleOutcome(oracles, outcome) =>
|
||||||
(Arr.from(oracles.map(o => Str(o.announcement.hex))),
|
(
|
||||||
Str(outcome.outcome))
|
Arr.from(oracles.map(o => Str(o.announcement.hex))),
|
||||||
|
Str(outcome.outcome)
|
||||||
|
)
|
||||||
case numeric: NumericOracleOutcome =>
|
case numeric: NumericOracleOutcome =>
|
||||||
(Arr.from(numeric.oracles.map(_.announcement.hex)),
|
(
|
||||||
Arr.from(numeric.outcomes.map(o => Arr.from(o.digits))))
|
Arr.from(numeric.oracles.map(_.announcement.hex)),
|
||||||
|
Arr.from(numeric.outcomes.map(o => Arr.from(o.digits)))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Obj(
|
Obj(
|
||||||
@ -1063,9 +1134,11 @@ object Picklers {
|
|||||||
"contractId" -> Str(contractId.toHex),
|
"contractId" -> Str(contractId.toHex),
|
||||||
"contractInfo" -> Str(contractInfo.hex),
|
"contractInfo" -> Str(contractInfo.hex),
|
||||||
"contractMaturity" -> Num(
|
"contractMaturity" -> Num(
|
||||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
timeouts.contractMaturity.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"contractTimeout" -> Num(
|
"contractTimeout" -> Num(
|
||||||
timeouts.contractTimeout.toUInt32.toLong.toDouble),
|
timeouts.contractTimeout.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"feeRate" -> Num(feeRate.toLong.toDouble),
|
"feeRate" -> Num(feeRate.toLong.toDouble),
|
||||||
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
||||||
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
||||||
@ -1076,9 +1149,11 @@ object Picklers {
|
|||||||
"outcomes" -> outcomesJs,
|
"outcomes" -> outcomesJs,
|
||||||
"oracles" -> oraclesJs,
|
"oracles" -> oraclesJs,
|
||||||
PicklerKeys.myPayout -> Num(
|
PicklerKeys.myPayout -> Num(
|
||||||
remoteClaimed.myPayout.satoshis.toLong.toDouble),
|
remoteClaimed.myPayout.satoshis.toLong.toDouble
|
||||||
|
),
|
||||||
counterPartyPayoutKey -> Num(
|
counterPartyPayoutKey -> Num(
|
||||||
remoteClaimed.counterPartyPayout.satoshis.toLong.toDouble),
|
remoteClaimed.counterPartyPayout.satoshis.toLong.toDouble
|
||||||
|
),
|
||||||
PicklerKeys.pnl -> Num(remoteClaimed.pnl.satoshis.toLong.toDouble),
|
PicklerKeys.pnl -> Num(remoteClaimed.pnl.satoshis.toLong.toDouble),
|
||||||
PicklerKeys.rateOfReturn -> Num(remoteClaimed.rateOfReturn.toDouble),
|
PicklerKeys.rateOfReturn -> Num(remoteClaimed.rateOfReturn.toDouble),
|
||||||
"payoutAddress" -> writeJs(payoutAddress),
|
"payoutAddress" -> writeJs(payoutAddress),
|
||||||
@ -1097,9 +1172,11 @@ object Picklers {
|
|||||||
"contractId" -> Str(contractId.toHex),
|
"contractId" -> Str(contractId.toHex),
|
||||||
"contractInfo" -> Str(contractInfo.hex),
|
"contractInfo" -> Str(contractInfo.hex),
|
||||||
"contractMaturity" -> Num(
|
"contractMaturity" -> Num(
|
||||||
timeouts.contractMaturity.toUInt32.toLong.toDouble),
|
timeouts.contractMaturity.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"contractTimeout" -> Num(
|
"contractTimeout" -> Num(
|
||||||
timeouts.contractTimeout.toUInt32.toLong.toDouble),
|
timeouts.contractTimeout.toUInt32.toLong.toDouble
|
||||||
|
),
|
||||||
"feeRate" -> Num(feeRate.toLong.toDouble),
|
"feeRate" -> Num(feeRate.toLong.toDouble),
|
||||||
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
|
||||||
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
|
||||||
@ -1108,7 +1185,8 @@ object Picklers {
|
|||||||
"closingTxId" -> Str(closingTxId.hex),
|
"closingTxId" -> Str(closingTxId.hex),
|
||||||
PicklerKeys.myPayout -> Num(refunded.myPayout.satoshis.toLong.toDouble),
|
PicklerKeys.myPayout -> Num(refunded.myPayout.satoshis.toLong.toDouble),
|
||||||
counterPartyPayoutKey -> Num(
|
counterPartyPayoutKey -> Num(
|
||||||
refunded.counterPartyPayout.satoshis.toLong.toDouble),
|
refunded.counterPartyPayout.satoshis.toLong.toDouble
|
||||||
|
),
|
||||||
PicklerKeys.pnl -> Num(refunded.pnl.satoshis.toLong.toDouble),
|
PicklerKeys.pnl -> Num(refunded.pnl.satoshis.toLong.toDouble),
|
||||||
PicklerKeys.rateOfReturn -> Num(refunded.rateOfReturn.toDouble),
|
PicklerKeys.rateOfReturn -> Num(refunded.rateOfReturn.toDouble),
|
||||||
"payoutAddress" -> writeJs(payoutAddress),
|
"payoutAddress" -> writeJs(payoutAddress),
|
||||||
@ -1161,11 +1239,13 @@ object Picklers {
|
|||||||
val message = Try(obj("message").str).toOption
|
val message = Try(obj("message").str).toOption
|
||||||
val receivedAt = Instant.ofEpochSecond(obj("receivedAt").num.toLong)
|
val receivedAt = Instant.ofEpochSecond(obj("receivedAt").num.toLong)
|
||||||
val offerTLV = DLCOfferTLV.fromHex(obj("offerTLV").str)
|
val offerTLV = DLCOfferTLV.fromHex(obj("offerTLV").str)
|
||||||
IncomingDLCOfferDb(hash = hash,
|
IncomingDLCOfferDb(
|
||||||
peer = peer,
|
hash = hash,
|
||||||
message = message,
|
peer = peer,
|
||||||
receivedAt = receivedAt,
|
message = message,
|
||||||
offerTLV = offerTLV)
|
receivedAt = receivedAt,
|
||||||
|
offerTLV = offerTLV
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val dlcOfferRemoveR: Reader[Sha256Digest] =
|
implicit val dlcOfferRemoveR: Reader[Sha256Digest] =
|
||||||
@ -1202,8 +1282,10 @@ object Picklers {
|
|||||||
lazy val payoutAddress: Option[PayoutAddress] = payoutAddressJs match {
|
lazy val payoutAddress: Option[PayoutAddress] = payoutAddressJs match {
|
||||||
case json: Obj =>
|
case json: Obj =>
|
||||||
json("address").strOpt.map(a =>
|
json("address").strOpt.map(a =>
|
||||||
PayoutAddress(BitcoinAddress.fromString(a),
|
PayoutAddress(
|
||||||
json("isExternal").boolOpt.getOrElse(false)))
|
BitcoinAddress.fromString(a),
|
||||||
|
json("isExternal").boolOpt.getOrElse(false)
|
||||||
|
))
|
||||||
case Null => None
|
case Null => None
|
||||||
case v: Value =>
|
case v: Value =>
|
||||||
throw new IllegalArgumentException(s"Unexpected payout address $v")
|
throw new IllegalArgumentException(s"Unexpected payout address $v")
|
||||||
@ -1228,8 +1310,10 @@ object Picklers {
|
|||||||
|
|
||||||
lazy val oracleOutcome = outcomes.head match {
|
lazy val oracleOutcome = outcomes.head match {
|
||||||
case outcome: EnumOutcome =>
|
case outcome: EnumOutcome =>
|
||||||
EnumOracleOutcome(oracles.asInstanceOf[Vector[EnumSingleOracleInfo]],
|
EnumOracleOutcome(
|
||||||
outcome)
|
oracles.asInstanceOf[Vector[EnumSingleOracleInfo]],
|
||||||
|
outcome
|
||||||
|
)
|
||||||
case UnsignedNumericOutcome(_) =>
|
case UnsignedNumericOutcome(_) =>
|
||||||
val numericOutcomes =
|
val numericOutcomes =
|
||||||
outcomes.map(_.asInstanceOf[UnsignedNumericOutcome])
|
outcomes.map(_.asInstanceOf[UnsignedNumericOutcome])
|
||||||
@ -1377,8 +1461,10 @@ object Picklers {
|
|||||||
peerOpt
|
peerOpt
|
||||||
)
|
)
|
||||||
case DLCState.RemoteClaimed =>
|
case DLCState.RemoteClaimed =>
|
||||||
require(oracleSigs.size == 1,
|
require(
|
||||||
"Remote claimed should only have one oracle sig")
|
oracleSigs.size == 1,
|
||||||
|
"Remote claimed should only have one oracle sig"
|
||||||
|
)
|
||||||
RemoteClaimed(
|
RemoteClaimed(
|
||||||
dlcId,
|
dlcId,
|
||||||
isInitiator,
|
isInitiator,
|
||||||
@ -1425,13 +1511,17 @@ object Picklers {
|
|||||||
writer[Obj].comap { walletAccounting: DLCWalletAccounting =>
|
writer[Obj].comap { walletAccounting: DLCWalletAccounting =>
|
||||||
Obj(
|
Obj(
|
||||||
PicklerKeys.myCollateral -> Num(
|
PicklerKeys.myCollateral -> Num(
|
||||||
walletAccounting.myCollateral.satoshis.toLong.toDouble),
|
walletAccounting.myCollateral.satoshis.toLong.toDouble
|
||||||
|
),
|
||||||
PicklerKeys.theirCollateral -> Num(
|
PicklerKeys.theirCollateral -> Num(
|
||||||
walletAccounting.theirCollateral.satoshis.toLong.toDouble),
|
walletAccounting.theirCollateral.satoshis.toLong.toDouble
|
||||||
|
),
|
||||||
PicklerKeys.myPayout -> Num(
|
PicklerKeys.myPayout -> Num(
|
||||||
walletAccounting.myPayout.satoshis.toLong.toDouble),
|
walletAccounting.myPayout.satoshis.toLong.toDouble
|
||||||
|
),
|
||||||
PicklerKeys.theirPayout -> Num(
|
PicklerKeys.theirPayout -> Num(
|
||||||
walletAccounting.theirPayout.satoshis.toLong.toDouble),
|
walletAccounting.theirPayout.satoshis.toLong.toDouble
|
||||||
|
),
|
||||||
PicklerKeys.pnl -> Num(walletAccounting.pnl.satoshis.toLong.toDouble),
|
PicklerKeys.pnl -> Num(walletAccounting.pnl.satoshis.toLong.toDouble),
|
||||||
PicklerKeys.rateOfReturn -> Num(walletAccounting.rateOfReturn.toDouble)
|
PicklerKeys.rateOfReturn -> Num(walletAccounting.rateOfReturn.toDouble)
|
||||||
)
|
)
|
||||||
@ -1441,7 +1531,8 @@ object Picklers {
|
|||||||
implicit val mnemonicCodePickler: ReadWriter[MnemonicCode] =
|
implicit val mnemonicCodePickler: ReadWriter[MnemonicCode] =
|
||||||
readwriter[String].bimap(
|
readwriter[String].bimap(
|
||||||
_.words.mkString(" "),
|
_.words.mkString(" "),
|
||||||
str => MnemonicCode.fromWords(str.split(' ').toVector))
|
str => MnemonicCode.fromWords(str.split(' ').toVector)
|
||||||
|
)
|
||||||
|
|
||||||
implicit val extPrivateKeyPickler: ReadWriter[ExtPrivateKey] =
|
implicit val extPrivateKeyPickler: ReadWriter[ExtPrivateKey] =
|
||||||
readwriter[String].bimap(ExtKey.toString, ExtPrivateKey.fromString)
|
readwriter[String].bimap(ExtKey.toString, ExtPrivateKey.fromString)
|
||||||
@ -1559,13 +1650,16 @@ object Picklers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def writeCompactFilterDb(
|
private def writeCompactFilterDb(
|
||||||
compactFilterDb: CompactFilterDb): ujson.Obj = {
|
compactFilterDb: CompactFilterDb
|
||||||
|
): ujson.Obj = {
|
||||||
ujson.Obj(
|
ujson.Obj(
|
||||||
PicklerKeys.hashKey -> ujson.Str(compactFilterDb.hashBE.hex),
|
PicklerKeys.hashKey -> ujson.Str(compactFilterDb.hashBE.hex),
|
||||||
PicklerKeys.filterTypeKey -> ujson.Str(
|
PicklerKeys.filterTypeKey -> ujson.Str(
|
||||||
compactFilterDb.filterType.toString),
|
compactFilterDb.filterType.toString
|
||||||
|
),
|
||||||
PicklerKeys.compactFilterBytesKey -> ujson.Str(
|
PicklerKeys.compactFilterBytesKey -> ujson.Str(
|
||||||
compactFilterDb.bytes.toHex),
|
compactFilterDb.bytes.toHex
|
||||||
|
),
|
||||||
PicklerKeys.heightKey -> ujson.Num(compactFilterDb.height),
|
PicklerKeys.heightKey -> ujson.Num(compactFilterDb.height),
|
||||||
PicklerKeys.blockHashKey -> ujson.Str(compactFilterDb.blockHashBE.hex)
|
PicklerKeys.blockHashKey -> ujson.Str(compactFilterDb.blockHashBE.hex)
|
||||||
)
|
)
|
||||||
@ -1590,7 +1684,8 @@ object Picklers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def writeCompactFilterHeaderDb(
|
private def writeCompactFilterHeaderDb(
|
||||||
filterHeaderDb: CompactFilterHeaderDb): ujson.Obj = {
|
filterHeaderDb: CompactFilterHeaderDb
|
||||||
|
): ujson.Obj = {
|
||||||
ujson.Obj(
|
ujson.Obj(
|
||||||
PicklerKeys.hashKey -> ujson.Str(filterHeaderDb.hashBE.hex),
|
PicklerKeys.hashKey -> ujson.Str(filterHeaderDb.hashBE.hex),
|
||||||
PicklerKeys.filterHashKey -> ujson.Str(filterHeaderDb.filterHashBE.hex),
|
PicklerKeys.filterHashKey -> ujson.Str(filterHeaderDb.filterHashBE.hex),
|
||||||
@ -1602,7 +1697,8 @@ object Picklers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def readCompactFilterHeaderDb(
|
private def readCompactFilterHeaderDb(
|
||||||
obj: ujson.Obj): CompactFilterHeaderDb = {
|
obj: ujson.Obj
|
||||||
|
): CompactFilterHeaderDb = {
|
||||||
val hash = DoubleSha256DigestBE.fromHex(obj(PicklerKeys.hashKey).str)
|
val hash = DoubleSha256DigestBE.fromHex(obj(PicklerKeys.hashKey).str)
|
||||||
val filterHash =
|
val filterHash =
|
||||||
DoubleSha256DigestBE.fromHex(obj(PicklerKeys.filterHashKey).str)
|
DoubleSha256DigestBE.fromHex(obj(PicklerKeys.filterHashKey).str)
|
||||||
@ -1611,11 +1707,13 @@ object Picklers {
|
|||||||
val blockHash =
|
val blockHash =
|
||||||
DoubleSha256DigestBE.fromHex(obj(PicklerKeys.blockHashKey).str)
|
DoubleSha256DigestBE.fromHex(obj(PicklerKeys.blockHashKey).str)
|
||||||
val height = obj(PicklerKeys.heightKey).num
|
val height = obj(PicklerKeys.heightKey).num
|
||||||
CompactFilterHeaderDb(hashBE = hash,
|
CompactFilterHeaderDb(
|
||||||
filterHashBE = filterHash,
|
hashBE = hash,
|
||||||
previousFilterHeaderBE = previousFilterHeader,
|
filterHashBE = filterHash,
|
||||||
blockHashBE = blockHash,
|
previousFilterHeaderBE = previousFilterHeader,
|
||||||
height = height.toInt)
|
blockHashBE = blockHash,
|
||||||
|
height = height.toInt
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def writeContactDb(contact: DLCContactDb): ujson.Obj = {
|
private def writeContactDb(contact: DLCContactDb): ujson.Obj = {
|
||||||
|
@ -4,8 +4,9 @@ import play.api.libs.json._
|
|||||||
|
|
||||||
sealed abstract class SerializerUtil {
|
sealed abstract class SerializerUtil {
|
||||||
|
|
||||||
def processJsNumberBigInt[T](numFunc: BigInt => T)(
|
def processJsNumberBigInt[T](
|
||||||
json: JsValue): JsResult[T] =
|
numFunc: BigInt => T
|
||||||
|
)(json: JsValue): JsResult[T] =
|
||||||
json match {
|
json match {
|
||||||
case JsNumber(nDecimal) =>
|
case JsNumber(nDecimal) =>
|
||||||
val nOpt = nDecimal.toBigIntExact
|
val nOpt = nDecimal.toBigIntExact
|
||||||
@ -54,14 +55,15 @@ sealed abstract class SerializerUtil {
|
|||||||
SerializerUtil.buildJsErrorMsg("jsstring", err)
|
SerializerUtil.buildJsErrorMsg("jsstring", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
def processJsStringOpt[T](f: String => Option[T])(
|
def processJsStringOpt[T](
|
||||||
jsValue: JsValue): JsResult[T] = {
|
f: String => Option[T]
|
||||||
|
)(jsValue: JsValue): JsResult[T] = {
|
||||||
jsValue match {
|
jsValue match {
|
||||||
case JsString(key) =>
|
case JsString(key) =>
|
||||||
val tOpt = f(key)
|
val tOpt = f(key)
|
||||||
tOpt match {
|
tOpt match {
|
||||||
case Some(t) => JsSuccess(t)
|
case Some(t) => JsSuccess(t)
|
||||||
case None => SerializerUtil.buildErrorMsg("invalid jsstring", jsValue)
|
case None => SerializerUtil.buildErrorMsg("invalid jsstring", jsValue)
|
||||||
}
|
}
|
||||||
case err @ (_: JsNumber | _: JsObject | _: JsArray | JsNull |
|
case err @ (_: JsNumber | _: JsObject | _: JsArray | JsNull |
|
||||||
_: JsBoolean) =>
|
_: JsBoolean) =>
|
||||||
|
@ -69,13 +69,15 @@ object WsPicklers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def writeChainNotification(
|
private def writeChainNotification(
|
||||||
notification: ChainNotification[_]): ujson.Obj = {
|
notification: ChainNotification[_]
|
||||||
|
): ujson.Obj = {
|
||||||
val payloadJson: ujson.Value = notification match {
|
val payloadJson: ujson.Value = notification match {
|
||||||
case BlockProcessedNotification(block) =>
|
case BlockProcessedNotification(block) =>
|
||||||
upickle.default.writeJs(block)(Picklers.getBlockHeaderResultPickler)
|
upickle.default.writeJs(block)(Picklers.getBlockHeaderResultPickler)
|
||||||
case CompactFilterHeaderProcessedNotification(filterHeader) =>
|
case CompactFilterHeaderProcessedNotification(filterHeader) =>
|
||||||
upickle.default.writeJs(filterHeader)(
|
upickle.default.writeJs(filterHeader)(
|
||||||
Picklers.compactFilterHeaderPickler)
|
Picklers.compactFilterHeaderPickler
|
||||||
|
)
|
||||||
case CompactFilterProcessedNotification(filter) =>
|
case CompactFilterProcessedNotification(filter) =>
|
||||||
upickle.default.writeJs(filter)(Picklers.compactFilterDbPickler)
|
upickle.default.writeJs(filter)(Picklers.compactFilterDbPickler)
|
||||||
case SyncFlagChangedNotification(syncing) =>
|
case SyncFlagChangedNotification(syncing) =>
|
||||||
@ -115,7 +117,8 @@ object WsPicklers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def writeWalletNotification(
|
private def writeWalletNotification(
|
||||||
notification: WalletNotification[_]): ujson.Obj = {
|
notification: WalletNotification[_]
|
||||||
|
): ujson.Obj = {
|
||||||
val payloadJson: ujson.Value = notification match {
|
val payloadJson: ujson.Value = notification match {
|
||||||
case TxBroadcastNotification(tx) =>
|
case TxBroadcastNotification(tx) =>
|
||||||
upickle.default.writeJs(tx)(Picklers.transactionPickler)
|
upickle.default.writeJs(tx)(Picklers.transactionPickler)
|
||||||
@ -184,7 +187,8 @@ object WsPicklers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def writeTorNotification(
|
private def writeTorNotification(
|
||||||
notification: TorNotification[_]): ujson.Obj = {
|
notification: TorNotification[_]
|
||||||
|
): ujson.Obj = {
|
||||||
val payloadJson = notification.`type` match {
|
val payloadJson = notification.`type` match {
|
||||||
case TorWsType.TorStarted =>
|
case TorWsType.TorStarted =>
|
||||||
ujson.Null
|
ujson.Null
|
||||||
@ -206,12 +210,15 @@ object WsPicklers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def writeDLCNodeNotification(
|
private def writeDLCNodeNotification(
|
||||||
notification: DLCNodeNotification[_]): ujson.Obj = {
|
notification: DLCNodeNotification[_]
|
||||||
|
): ujson.Obj = {
|
||||||
def addr2str(address: InetSocketAddress) =
|
def addr2str(address: InetSocketAddress) =
|
||||||
address.getHostName + ":" + address.getPort
|
address.getHostName + ":" + address.getPort
|
||||||
def failure2obj(payload: (Sha256Digest, String)): ujson.Obj = {
|
def failure2obj(payload: (Sha256Digest, String)): ujson.Obj = {
|
||||||
ujson.Obj(PicklerKeys.idKey -> writeJs(payload._1.hex),
|
ujson.Obj(
|
||||||
PicklerKeys.errorKey -> writeJs(payload._2))
|
PicklerKeys.idKey -> writeJs(payload._1.hex),
|
||||||
|
PicklerKeys.errorKey -> writeJs(payload._2)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
val payloadJson: ujson.Value = notification match {
|
val payloadJson: ujson.Value = notification match {
|
||||||
case DLCNodeConnectionInitiated(address) =>
|
case DLCNodeConnectionInitiated(address) =>
|
||||||
@ -238,13 +245,16 @@ object WsPicklers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def readDLCNodeNotification(
|
private def readDLCNodeNotification(
|
||||||
obj: ujson.Obj): DLCNodeNotification[_] = {
|
obj: ujson.Obj
|
||||||
|
): DLCNodeNotification[_] = {
|
||||||
val typeObj = read[DLCNodeWsType](obj(PicklerKeys.typeKey))
|
val typeObj = read[DLCNodeWsType](obj(PicklerKeys.typeKey))
|
||||||
val payloadObj = obj(PicklerKeys.payloadKey)
|
val payloadObj = obj(PicklerKeys.payloadKey)
|
||||||
|
|
||||||
def obj2failure(payload: ujson.Value): (Sha256Digest, String) = {
|
def obj2failure(payload: ujson.Value): (Sha256Digest, String) = {
|
||||||
(Sha256Digest.fromHex(payload.obj(PicklerKeys.idKey).str),
|
(
|
||||||
payload.obj(PicklerKeys.errorKey).str)
|
Sha256Digest.fromHex(payload.obj(PicklerKeys.idKey).str),
|
||||||
|
payload.obj(PicklerKeys.errorKey).str
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
typeObj match {
|
typeObj match {
|
||||||
@ -278,25 +288,29 @@ object WsPicklers {
|
|||||||
implicit val newAddressPickler: ReadWriter[NewAddressNotification] = {
|
implicit val newAddressPickler: ReadWriter[NewAddressNotification] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeWalletNotification(_),
|
writeWalletNotification(_),
|
||||||
readWalletNotification(_).asInstanceOf[NewAddressNotification])
|
readWalletNotification(_).asInstanceOf[NewAddressNotification]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val txProcessedPickler: ReadWriter[TxProcessedNotification] = {
|
implicit val txProcessedPickler: ReadWriter[TxProcessedNotification] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeWalletNotification(_),
|
writeWalletNotification(_),
|
||||||
readWalletNotification(_).asInstanceOf[TxProcessedNotification])
|
readWalletNotification(_).asInstanceOf[TxProcessedNotification]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val txBroadcastPickler: ReadWriter[TxBroadcastNotification] = {
|
implicit val txBroadcastPickler: ReadWriter[TxBroadcastNotification] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeWalletNotification(_),
|
writeWalletNotification(_),
|
||||||
readWalletNotification(_).asInstanceOf[TxBroadcastNotification])
|
readWalletNotification(_).asInstanceOf[TxBroadcastNotification]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val reservedUtxosPickler: ReadWriter[ReservedUtxosNotification] = {
|
implicit val reservedUtxosPickler: ReadWriter[ReservedUtxosNotification] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeWalletNotification(_),
|
writeWalletNotification(_),
|
||||||
readWalletNotification(_).asInstanceOf[ReservedUtxosNotification])
|
readWalletNotification(_).asInstanceOf[ReservedUtxosNotification]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val rescanPickler: ReadWriter[RescanComplete] = {
|
implicit val rescanPickler: ReadWriter[RescanComplete] = {
|
||||||
@ -313,8 +327,8 @@ object WsPicklers {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val dlcNodeNotificationPickler: ReadWriter[
|
implicit val dlcNodeNotificationPickler
|
||||||
DLCNodeNotification[_]] = {
|
: ReadWriter[DLCNodeNotification[_]] = {
|
||||||
readwriter[ujson.Obj]
|
readwriter[ujson.Obj]
|
||||||
.bimap(writeDLCNodeNotification, readDLCNodeNotification)
|
.bimap(writeDLCNodeNotification, readDLCNodeNotification)
|
||||||
}
|
}
|
||||||
@ -334,8 +348,8 @@ object WsPicklers {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val compactFilterHeaderProcessedPickler: ReadWriter[
|
implicit val compactFilterHeaderProcessedPickler
|
||||||
CompactFilterHeaderProcessedNotification] = {
|
: ReadWriter[CompactFilterHeaderProcessedNotification] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeChainNotification(_),
|
writeChainNotification(_),
|
||||||
readChainNotification(_)
|
readChainNotification(_)
|
||||||
@ -343,16 +357,16 @@ object WsPicklers {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val compactFilterProcessedPickler: ReadWriter[
|
implicit val compactFilterProcessedPickler
|
||||||
CompactFilterProcessedNotification] = {
|
: ReadWriter[CompactFilterProcessedNotification] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeChainNotification(_),
|
writeChainNotification(_),
|
||||||
readChainNotification(_).asInstanceOf[CompactFilterProcessedNotification]
|
readChainNotification(_).asInstanceOf[CompactFilterProcessedNotification]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val syncFlagChangedPickler: ReadWriter[
|
implicit val syncFlagChangedPickler
|
||||||
SyncFlagChangedNotification] = {
|
: ReadWriter[SyncFlagChangedNotification] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeChainNotification(_),
|
writeChainNotification(_),
|
||||||
readChainNotification(_).asInstanceOf[SyncFlagChangedNotification]
|
readChainNotification(_).asInstanceOf[SyncFlagChangedNotification]
|
||||||
@ -362,83 +376,96 @@ object WsPicklers {
|
|||||||
implicit val dlcStateChangePickler: ReadWriter[DLCStateChangeNotification] = {
|
implicit val dlcStateChangePickler: ReadWriter[DLCStateChangeNotification] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeWalletNotification(_),
|
writeWalletNotification(_),
|
||||||
readWalletNotification(_).asInstanceOf[DLCStateChangeNotification])
|
readWalletNotification(_).asInstanceOf[DLCStateChangeNotification]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val dlcOfferAddPickler: ReadWriter[DLCOfferAddNotification] = {
|
implicit val dlcOfferAddPickler: ReadWriter[DLCOfferAddNotification] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeWalletNotification(_),
|
writeWalletNotification(_),
|
||||||
readWalletNotification(_).asInstanceOf[DLCOfferAddNotification])
|
readWalletNotification(_).asInstanceOf[DLCOfferAddNotification]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val dlcOfferRemovePickler: ReadWriter[DLCOfferRemoveNotification] = {
|
implicit val dlcOfferRemovePickler: ReadWriter[DLCOfferRemoveNotification] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeWalletNotification(_),
|
writeWalletNotification(_),
|
||||||
readWalletNotification(_).asInstanceOf[DLCOfferRemoveNotification])
|
readWalletNotification(_).asInstanceOf[DLCOfferRemoveNotification]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val torStartedPickler: ReadWriter[
|
implicit val torStartedPickler
|
||||||
TorNotification.TorStartedNotification.type] = {
|
: ReadWriter[TorNotification.TorStartedNotification.type] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeTorNotification(_),
|
writeTorNotification(_),
|
||||||
readTorNotification(_)
|
readTorNotification(_)
|
||||||
.asInstanceOf[TorNotification.TorStartedNotification.type])
|
.asInstanceOf[TorNotification.TorStartedNotification.type]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val dlcNodeConnectionInitiatedPickler: ReadWriter[
|
implicit val dlcNodeConnectionInitiatedPickler
|
||||||
DLCNodeConnectionInitiated] = {
|
: ReadWriter[DLCNodeConnectionInitiated] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeDLCNodeNotification(_),
|
writeDLCNodeNotification(_),
|
||||||
readDLCNodeNotification(_).asInstanceOf[DLCNodeConnectionInitiated])
|
readDLCNodeNotification(_).asInstanceOf[DLCNodeConnectionInitiated]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val dlcNodeConnectionFailedPickler: ReadWriter[
|
implicit val dlcNodeConnectionFailedPickler
|
||||||
DLCNodeConnectionFailed] = {
|
: ReadWriter[DLCNodeConnectionFailed] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeDLCNodeNotification(_),
|
writeDLCNodeNotification(_),
|
||||||
readDLCNodeNotification(_).asInstanceOf[DLCNodeConnectionFailed])
|
readDLCNodeNotification(_).asInstanceOf[DLCNodeConnectionFailed]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val dlcNodeConnectionEstablishedPickler: ReadWriter[
|
implicit val dlcNodeConnectionEstablishedPickler
|
||||||
DLCNodeConnectionEstablished] = {
|
: ReadWriter[DLCNodeConnectionEstablished] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeDLCNodeNotification(_),
|
writeDLCNodeNotification(_),
|
||||||
readDLCNodeNotification(_).asInstanceOf[DLCNodeConnectionEstablished])
|
readDLCNodeNotification(_).asInstanceOf[DLCNodeConnectionEstablished]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val dlcAcceptSucceedPickler: ReadWriter[DLCAcceptSucceed] = {
|
implicit val dlcAcceptSucceedPickler: ReadWriter[DLCAcceptSucceed] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeDLCNodeNotification(_),
|
writeDLCNodeNotification(_),
|
||||||
readDLCNodeNotification(_).asInstanceOf[DLCAcceptSucceed])
|
readDLCNodeNotification(_).asInstanceOf[DLCAcceptSucceed]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val dlcAcceptFailedPickler: ReadWriter[DLCAcceptFailed] = {
|
implicit val dlcAcceptFailedPickler: ReadWriter[DLCAcceptFailed] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeDLCNodeNotification(_),
|
writeDLCNodeNotification(_),
|
||||||
readDLCNodeNotification(_).asInstanceOf[DLCAcceptFailed])
|
readDLCNodeNotification(_).asInstanceOf[DLCAcceptFailed]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val dlcSignSucceedPickler: ReadWriter[DLCSignSucceed] = {
|
implicit val dlcSignSucceedPickler: ReadWriter[DLCSignSucceed] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeDLCNodeNotification(_),
|
writeDLCNodeNotification(_),
|
||||||
readDLCNodeNotification(_).asInstanceOf[DLCSignSucceed])
|
readDLCNodeNotification(_).asInstanceOf[DLCSignSucceed]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val dlcSignFailedPickler: ReadWriter[DLCSignFailed] = {
|
implicit val dlcSignFailedPickler: ReadWriter[DLCSignFailed] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeDLCNodeNotification(_),
|
writeDLCNodeNotification(_),
|
||||||
readDLCNodeNotification(_).asInstanceOf[DLCSignFailed])
|
readDLCNodeNotification(_).asInstanceOf[DLCSignFailed]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val dlcOfferSendSucceedPickler: ReadWriter[DLCOfferSendSucceed] = {
|
implicit val dlcOfferSendSucceedPickler: ReadWriter[DLCOfferSendSucceed] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeDLCNodeNotification(_),
|
writeDLCNodeNotification(_),
|
||||||
readDLCNodeNotification(_).asInstanceOf[DLCOfferSendSucceed])
|
readDLCNodeNotification(_).asInstanceOf[DLCOfferSendSucceed]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val dlcOfferSendFailedPickler: ReadWriter[DLCOfferSendFailed] = {
|
implicit val dlcOfferSendFailedPickler: ReadWriter[DLCOfferSendFailed] = {
|
||||||
readwriter[ujson.Obj].bimap(
|
readwriter[ujson.Obj].bimap(
|
||||||
writeDLCNodeNotification(_),
|
writeDLCNodeNotification(_),
|
||||||
readDLCNodeNotification(_).asInstanceOf[DLCOfferSendFailed])
|
readDLCNodeNotification(_).asInstanceOf[DLCOfferSendFailed]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,15 @@ import org.bitcoins.commons.config.AppConfig
|
|||||||
|
|
||||||
import java.nio.file.{Path, Paths}
|
import java.nio.file.{Path, Paths}
|
||||||
|
|
||||||
/** Parses the correct datadir given the possible input sources for datadir config
|
/** Parses the correct datadir given the possible input sources for datadir
|
||||||
* 1. The --datadir command line flag
|
* config
|
||||||
* 2. Inferring the datadir based on the bitcoin network configured
|
* 1. The --datadir command line flag 2. Inferring the datadir based on the
|
||||||
* 3. ??? Anything else i'm forgetting ????
|
* bitcoin network configured 3. ??? Anything else i'm forgetting ????
|
||||||
*/
|
*/
|
||||||
case class DatadirParser(
|
case class DatadirParser(
|
||||||
serverArgs: ServerArgParser,
|
serverArgs: ServerArgParser,
|
||||||
customFinalDirOpt: Option[String]) {
|
customFinalDirOpt: Option[String]
|
||||||
|
) {
|
||||||
|
|
||||||
/** Sets the default data dir, overridden by the --datadir option */
|
/** Sets the default data dir, overridden by the --datadir option */
|
||||||
private lazy val datadirPath: Path = serverArgs.datadirOpt match {
|
private lazy val datadirPath: Path = serverArgs.datadirOpt match {
|
||||||
@ -22,7 +23,8 @@ case class DatadirParser(
|
|||||||
|
|
||||||
lazy val datadirConfig: Config =
|
lazy val datadirConfig: Config =
|
||||||
ConfigFactory.parseString(
|
ConfigFactory.parseString(
|
||||||
s"bitcoin-s.datadir = ${AppConfig.safePathToString(datadirPath)}")
|
s"bitcoin-s.datadir = ${AppConfig.safePathToString(datadirPath)}"
|
||||||
|
)
|
||||||
|
|
||||||
lazy val networkConfig: Config = serverArgs.networkOpt match {
|
lazy val networkConfig: Config = serverArgs.networkOpt match {
|
||||||
case Some(network) =>
|
case Some(network) =>
|
||||||
@ -35,9 +37,11 @@ case class DatadirParser(
|
|||||||
serverArgs.configOpt match {
|
serverArgs.configOpt match {
|
||||||
case None =>
|
case None =>
|
||||||
AppConfig
|
AppConfig
|
||||||
.getBaseConfig(datadirPath,
|
.getBaseConfig(
|
||||||
AppConfig.DEFAULT_BITCOIN_S_CONF_FILE,
|
datadirPath,
|
||||||
Vector(networkConfig))
|
AppConfig.DEFAULT_BITCOIN_S_CONF_FILE,
|
||||||
|
Vector(networkConfig)
|
||||||
|
)
|
||||||
.withFallback(datadirConfig)
|
.withFallback(datadirConfig)
|
||||||
.resolve()
|
.resolve()
|
||||||
case Some(config) =>
|
case Some(config) =>
|
||||||
@ -55,11 +59,8 @@ case class DatadirParser(
|
|||||||
lazy val datadir: Path =
|
lazy val datadir: Path =
|
||||||
Paths.get(baseConfig.getString("bitcoin-s.datadir"))
|
Paths.get(baseConfig.getString("bitcoin-s.datadir"))
|
||||||
|
|
||||||
/** Directory specific for current network or custom dir
|
/** Directory specific for current network or custom dir Examples are
|
||||||
* Examples are
|
* HOME/.bitcoin-s/mainnet HOME/.bitcoin-s/testnet3 HOME/.bitcoin-s/oracle
|
||||||
* HOME/.bitcoin-s/mainnet
|
|
||||||
* HOME/.bitcoin-s/testnet3
|
|
||||||
* HOME/.bitcoin-s/oracle
|
|
||||||
*/
|
*/
|
||||||
def networkDir: Path =
|
def networkDir: Path =
|
||||||
DatadirUtil.getFinalDatadir(datadir, baseConfig, customFinalDirOpt)
|
DatadirUtil.getFinalDatadir(datadir, baseConfig, customFinalDirOpt)
|
||||||
|
@ -30,15 +30,15 @@ object DatadirUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets the final datadir for our applicatoin.
|
/** Sets the final datadir for our applicatoin. We allow useres to pass in a
|
||||||
* We allow useres to pass in a --datadir command line
|
* --datadir command line flag that needs to be used instead of the
|
||||||
* flag that needs to be used instead of the [[datadir]]
|
* [[datadir]] specified in bitcoin-s.conf
|
||||||
* specified in bitcoin-s.conf
|
|
||||||
*/
|
*/
|
||||||
def getFinalDatadir(
|
def getFinalDatadir(
|
||||||
datadir: Path,
|
datadir: Path,
|
||||||
baseConfig: Config,
|
baseConfig: Config,
|
||||||
customFinalDirOpt: Option[String] = None): Path = {
|
customFinalDirOpt: Option[String] = None
|
||||||
|
): Path = {
|
||||||
|
|
||||||
// $HOME is not set for windows, need to manually set it
|
// $HOME is not set for windows, need to manually set it
|
||||||
if (Properties.isWin) {
|
if (Properties.isWin) {
|
||||||
|
@ -30,7 +30,7 @@ trait NativeProcessFactory extends BitcoinSLogger {
|
|||||||
def startBinary(): Future[Unit] = FutureUtil.makeAsync { () =>
|
def startBinary(): Future[Unit] = FutureUtil.makeAsync { () =>
|
||||||
processOpt match {
|
processOpt match {
|
||||||
case Some(p) =>
|
case Some(p) =>
|
||||||
//don't do anything as it is already started
|
// don't do anything as it is already started
|
||||||
logger.info(s"Binary was already started! process=$p")
|
logger.info(s"Binary was already started! process=$p")
|
||||||
()
|
()
|
||||||
case None =>
|
case None =>
|
||||||
@ -46,8 +46,8 @@ trait NativeProcessFactory extends BitcoinSLogger {
|
|||||||
|
|
||||||
/** Stops the binary by destroying the underlying operating system process
|
/** Stops the binary by destroying the underlying operating system process
|
||||||
*
|
*
|
||||||
* If the client is a remote client (not started on the host operating system)
|
* If the client is a remote client (not started on the host operating
|
||||||
* this method is a no-op
|
* system) this method is a no-op
|
||||||
*/
|
*/
|
||||||
def stopBinary(): Future[Unit] = FutureUtil.makeAsync { () =>
|
def stopBinary(): Future[Unit] = FutureUtil.makeAsync { () =>
|
||||||
processOpt match {
|
processOpt match {
|
||||||
@ -58,7 +58,7 @@ trait NativeProcessFactory extends BitcoinSLogger {
|
|||||||
processOpt = None
|
processOpt = None
|
||||||
case None =>
|
case None =>
|
||||||
logger.info(s"No process found, binary wasn't started!")
|
logger.info(s"No process found, binary wasn't started!")
|
||||||
//no process running, nothing to do
|
// no process running, nothing to do
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,9 @@ import org.bitcoins.core.config._
|
|||||||
import java.nio.file.{Path, Paths}
|
import java.nio.file.{Path, Paths}
|
||||||
import scala.util.Properties
|
import scala.util.Properties
|
||||||
|
|
||||||
/** Parses arguments passed to the bitcoin-s app server as command line arguments
|
/** Parses arguments passed to the bitcoin-s app server as command line
|
||||||
* This does NOT consider things that exist in reference.conf or application.conf files
|
* arguments This does NOT consider things that exist in reference.conf or
|
||||||
|
* application.conf files
|
||||||
*/
|
*/
|
||||||
case class ServerArgParser(commandLineArgs: Vector[String]) {
|
case class ServerArgParser(commandLineArgs: Vector[String]) {
|
||||||
|
|
||||||
@ -70,10 +71,10 @@ case class ServerArgParser(commandLineArgs: Vector[String]) {
|
|||||||
/** The datadir passed in as a command line arg using --datadir */
|
/** The datadir passed in as a command line arg using --datadir */
|
||||||
lazy val datadirOpt: Option[Path] = dataDirIndexOpt.map { case (_, idx) =>
|
lazy val datadirOpt: Option[Path] = dataDirIndexOpt.map { case (_, idx) =>
|
||||||
val str = commandLineArgs(idx + 1)
|
val str = commandLineArgs(idx + 1)
|
||||||
//we only want the replace ~ if it is first in the file path
|
// we only want the replace ~ if it is first in the file path
|
||||||
//otherwise windows gets mangled as it can have parts of the file path containing ~
|
// otherwise windows gets mangled as it can have parts of the file path containing ~
|
||||||
//https://stackoverflow.com/a/7163455/967713
|
// https://stackoverflow.com/a/7163455/967713
|
||||||
//C:\Users\RUNNER~1\AppData\Local\Temp\bitcoin-s-13391384540028797275
|
// C:\Users\RUNNER~1\AppData\Local\Temp\bitcoin-s-13391384540028797275
|
||||||
val usableStr = str.replaceFirst("^~", Properties.userHome)
|
val usableStr = str.replaceFirst("^~", Properties.userHome)
|
||||||
Paths.get(usableStr)
|
Paths.get(usableStr)
|
||||||
}
|
}
|
||||||
@ -91,9 +92,9 @@ case class ServerArgParser(commandLineArgs: Vector[String]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts the given command line args into a Config object.
|
/** Converts the given command line args into a Config object. There is one
|
||||||
* There is one exclusion to this, we cannot write the --conf
|
* exclusion to this, we cannot write the --conf flag to the config file as
|
||||||
* flag to the config file as that is self referential
|
* that is self referential
|
||||||
*/
|
*/
|
||||||
def toConfig: Config = {
|
def toConfig: Config = {
|
||||||
val rpcPortString = rpcPortOpt match {
|
val rpcPortString = rpcPortOpt match {
|
||||||
@ -126,7 +127,7 @@ case class ServerArgParser(commandLineArgs: Vector[String]) {
|
|||||||
case None => ""
|
case None => ""
|
||||||
}
|
}
|
||||||
|
|
||||||
//omitting configOpt as i don't know if we can do anything with that?
|
// omitting configOpt as i don't know if we can do anything with that?
|
||||||
|
|
||||||
val all =
|
val all =
|
||||||
rpcPortString +
|
rpcPortString +
|
||||||
|
@ -18,7 +18,8 @@ object Cli extends App {
|
|||||||
} catch {
|
} catch {
|
||||||
case _: ConnectException =>
|
case _: ConnectException =>
|
||||||
printerr(
|
printerr(
|
||||||
"Connection refused! Check that the server is running and configured correctly.")
|
"Connection refused! Check that the server is running and configured correctly."
|
||||||
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,8 +103,8 @@ object CliReaders {
|
|||||||
EnumEventDescriptorV0TLV.fromHex
|
EnumEventDescriptorV0TLV.fromHex
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val digitDecompEventDescriptorReads: Read[
|
implicit val digitDecompEventDescriptorReads
|
||||||
DigitDecompositionEventDescriptorV0TLV] =
|
: Read[DigitDecompositionEventDescriptorV0TLV] =
|
||||||
new Read[DigitDecompositionEventDescriptorV0TLV] {
|
new Read[DigitDecompositionEventDescriptorV0TLV] {
|
||||||
override def arity: Int = 1
|
override def arity: Int = 1
|
||||||
|
|
||||||
@ -124,7 +124,8 @@ object CliReaders {
|
|||||||
override def arity: Int = 1
|
override def arity: Int = 1
|
||||||
override def reads: String => ContractDescriptorTLV = { str =>
|
override def reads: String => ContractDescriptorTLV = { str =>
|
||||||
upickle.default.read[ContractDescriptorV0TLV](str)(
|
upickle.default.read[ContractDescriptorV0TLV](str)(
|
||||||
Picklers.contractDescriptorV0)
|
Picklers.contractDescriptorV0
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,14 +240,16 @@ object CliReaders {
|
|||||||
|
|
||||||
val reads: String => BlockStamp = {
|
val reads: String => BlockStamp = {
|
||||||
case dateRe(year, month, day) =>
|
case dateRe(year, month, day) =>
|
||||||
val time = ZonedDateTime.of(year.toInt,
|
val time = ZonedDateTime.of(
|
||||||
month.toInt,
|
year.toInt,
|
||||||
day.toInt,
|
month.toInt,
|
||||||
0,
|
day.toInt,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
ZoneId.of("UTC"))
|
0,
|
||||||
|
ZoneId.of("UTC")
|
||||||
|
)
|
||||||
BlockTime(time)
|
BlockTime(time)
|
||||||
case str => BlockStamp.fromString(str)
|
case str => BlockStamp.fromString(str)
|
||||||
}
|
}
|
||||||
@ -310,8 +313,8 @@ object CliReaders {
|
|||||||
val reads: String => Sha256DigestBE = Sha256DigestBE.fromHex
|
val reads: String => Sha256DigestBE = Sha256DigestBE.fromHex
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val lockUnspentOutputParametersReads: Read[
|
implicit val lockUnspentOutputParametersReads
|
||||||
Vector[LockUnspentOutputParameter]] =
|
: Read[Vector[LockUnspentOutputParameter]] =
|
||||||
new Read[Vector[LockUnspentOutputParameter]] {
|
new Read[Vector[LockUnspentOutputParameter]] {
|
||||||
override val arity: Int = 1
|
override val arity: Int = 1
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -74,7 +74,8 @@ class OracleRoutesSpec
|
|||||||
Get() ~> route ~> check {
|
Get() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(
|
assert(
|
||||||
responseAs[String] == s"""{"result":"${key.hex}","error":null}""")
|
responseAs[String] == s"""{"result":"${key.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +91,8 @@ class OracleRoutesSpec
|
|||||||
Get() ~> route ~> check {
|
Get() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(
|
assert(
|
||||||
responseAs[String] == s"""{"result":"$testAddress","error":null}""")
|
responseAs[String] == s"""{"result":"$testAddress","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +107,10 @@ class OracleRoutesSpec
|
|||||||
Get() ~> route ~> check {
|
Get() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(
|
assert(
|
||||||
responseAs[String] == s"""{"result":["${dummyOracleEvent.eventName}"],"error":null}""")
|
responseAs[
|
||||||
|
String
|
||||||
|
] == s"""{"result":["${dummyOracleEvent.eventName}"],"error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +122,8 @@ class OracleRoutesSpec
|
|||||||
.returning(Future.successful(Some(dummyOracleEvent)))
|
.returning(Future.successful(Some(dummyOracleEvent)))
|
||||||
|
|
||||||
val route = oracleRoutes.handleCommand(
|
val route = oracleRoutes.handleCommand(
|
||||||
ServerCommand("getannouncement", Arr(eventName)))
|
ServerCommand("getannouncement", Arr(eventName))
|
||||||
|
)
|
||||||
|
|
||||||
val expected =
|
val expected =
|
||||||
s"""
|
s"""
|
||||||
@ -141,7 +147,7 @@ class OracleRoutesSpec
|
|||||||
| "error":null
|
| "error":null
|
||||||
|}
|
|}
|
||||||
|""".stripMargin
|
|""".stripMargin
|
||||||
.replaceAll("\\s", "") //strip whitespace
|
.replaceAll("\\s", "") // strip whitespace
|
||||||
|
|
||||||
val expectedJson: ujson.Value = ujson.read(Readable.fromString(expected))
|
val expectedJson: ujson.Value = ujson.read(Readable.fromString(expected))
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
@ -160,15 +166,19 @@ class OracleRoutesSpec
|
|||||||
|
|
||||||
val route =
|
val route =
|
||||||
oracleRoutes.handleCommand(
|
oracleRoutes.handleCommand(
|
||||||
ServerCommand("createenumannouncement",
|
ServerCommand(
|
||||||
Arr(Str("id"),
|
"createenumannouncement",
|
||||||
Str("2021-02-04T00:00:00Z"),
|
Arr(Str("id"), Str("2021-02-04T00:00:00Z"), Arr(Str("1"), Str("2")))
|
||||||
Arr(Str("1"), Str("2")))))
|
)
|
||||||
|
)
|
||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(responseAs[
|
assert(
|
||||||
String] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""")
|
responseAs[
|
||||||
|
String
|
||||||
|
] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,118 +192,159 @@ class OracleRoutesSpec
|
|||||||
oracleRoutes.handleCommand(
|
oracleRoutes.handleCommand(
|
||||||
ServerCommand(
|
ServerCommand(
|
||||||
"createenumannouncement",
|
"createenumannouncement",
|
||||||
Arr(Str("id"), Str("2021-02-04"), Arr(Str("1"), Str("2")))))
|
Arr(Str("id"), Str("2021-02-04"), Arr(Str("1"), Str("2")))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(responseAs[
|
assert(
|
||||||
String] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""")
|
responseAs[
|
||||||
|
String
|
||||||
|
] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"create numeric announcement" in {
|
"create numeric announcement" in {
|
||||||
(mockOracleApi
|
(mockOracleApi
|
||||||
.createNewDigitDecompAnnouncement(_: String,
|
.createNewDigitDecompAnnouncement(
|
||||||
_: Instant,
|
_: String,
|
||||||
_: UInt16,
|
_: Instant,
|
||||||
_: Boolean,
|
_: UInt16,
|
||||||
_: Int,
|
_: Boolean,
|
||||||
_: String,
|
_: Int,
|
||||||
_: Int32))
|
_: String,
|
||||||
.expects("id",
|
_: Int32
|
||||||
Instant.ofEpochSecond(1612396800),
|
))
|
||||||
UInt16(2),
|
.expects(
|
||||||
false,
|
"id",
|
||||||
17,
|
Instant.ofEpochSecond(1612396800),
|
||||||
"units",
|
UInt16(2),
|
||||||
Int32.zero)
|
false,
|
||||||
|
17,
|
||||||
|
"units",
|
||||||
|
Int32.zero
|
||||||
|
)
|
||||||
.returning(Future.successful(OracleAnnouncementV0TLV.dummy))
|
.returning(Future.successful(OracleAnnouncementV0TLV.dummy))
|
||||||
|
|
||||||
val route =
|
val route =
|
||||||
oracleRoutes.handleCommand(
|
oracleRoutes.handleCommand(
|
||||||
ServerCommand("createnumericannouncement",
|
ServerCommand(
|
||||||
Arr(Str("id"),
|
"createnumericannouncement",
|
||||||
Str("2021-02-04T00:00:00Z"),
|
Arr(
|
||||||
Num(0),
|
Str("id"),
|
||||||
Num(131000),
|
Str("2021-02-04T00:00:00Z"),
|
||||||
Str("units"),
|
Num(0),
|
||||||
Num(0))))
|
Num(131000),
|
||||||
|
Str("units"),
|
||||||
|
Num(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(responseAs[
|
assert(
|
||||||
String] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""")
|
responseAs[
|
||||||
|
String
|
||||||
|
] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"create numeric announcement with just date" in {
|
"create numeric announcement with just date" in {
|
||||||
(mockOracleApi
|
(mockOracleApi
|
||||||
.createNewDigitDecompAnnouncement(_: String,
|
.createNewDigitDecompAnnouncement(
|
||||||
_: Instant,
|
_: String,
|
||||||
_: UInt16,
|
_: Instant,
|
||||||
_: Boolean,
|
_: UInt16,
|
||||||
_: Int,
|
_: Boolean,
|
||||||
_: String,
|
_: Int,
|
||||||
_: Int32))
|
_: String,
|
||||||
.expects("id",
|
_: Int32
|
||||||
Instant.ofEpochSecond(1612396800),
|
))
|
||||||
UInt16(2),
|
.expects(
|
||||||
true,
|
"id",
|
||||||
17,
|
Instant.ofEpochSecond(1612396800),
|
||||||
"units",
|
UInt16(2),
|
||||||
Int32.zero)
|
true,
|
||||||
|
17,
|
||||||
|
"units",
|
||||||
|
Int32.zero
|
||||||
|
)
|
||||||
.returning(Future.successful(OracleAnnouncementV0TLV.dummy))
|
.returning(Future.successful(OracleAnnouncementV0TLV.dummy))
|
||||||
|
|
||||||
val route =
|
val route =
|
||||||
oracleRoutes.handleCommand(
|
oracleRoutes.handleCommand(
|
||||||
ServerCommand("createnumericannouncement",
|
ServerCommand(
|
||||||
Arr(Str("id"),
|
"createnumericannouncement",
|
||||||
Str("2021-02-04"),
|
Arr(
|
||||||
Num(-1),
|
Str("id"),
|
||||||
Num(131000),
|
Str("2021-02-04"),
|
||||||
Str("units"),
|
Num(-1),
|
||||||
Num(0))))
|
Num(131000),
|
||||||
|
Str("units"),
|
||||||
|
Num(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(responseAs[
|
assert(
|
||||||
String] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""")
|
responseAs[
|
||||||
|
String
|
||||||
|
] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"create digit decomp announcement" in {
|
"create digit decomp announcement" in {
|
||||||
(mockOracleApi
|
(mockOracleApi
|
||||||
.createNewDigitDecompAnnouncement(_: String,
|
.createNewDigitDecompAnnouncement(
|
||||||
_: Instant,
|
_: String,
|
||||||
_: UInt16,
|
_: Instant,
|
||||||
_: Boolean,
|
_: UInt16,
|
||||||
_: Int,
|
_: Boolean,
|
||||||
_: String,
|
_: Int,
|
||||||
_: Int32))
|
_: String,
|
||||||
.expects("id",
|
_: Int32
|
||||||
Instant.ofEpochSecond(1612396800),
|
))
|
||||||
UInt16(2),
|
.expects(
|
||||||
true,
|
"id",
|
||||||
17,
|
Instant.ofEpochSecond(1612396800),
|
||||||
"units",
|
UInt16(2),
|
||||||
Int32.zero)
|
true,
|
||||||
|
17,
|
||||||
|
"units",
|
||||||
|
Int32.zero
|
||||||
|
)
|
||||||
.returning(Future.successful(OracleAnnouncementV0TLV.dummy))
|
.returning(Future.successful(OracleAnnouncementV0TLV.dummy))
|
||||||
|
|
||||||
val route =
|
val route =
|
||||||
oracleRoutes.handleCommand(
|
oracleRoutes.handleCommand(
|
||||||
ServerCommand("createdigitdecompannouncement",
|
ServerCommand(
|
||||||
Arr(Str("id"),
|
"createdigitdecompannouncement",
|
||||||
Num(1612396800),
|
Arr(
|
||||||
Num(2),
|
Str("id"),
|
||||||
Bool(true),
|
Num(1612396800),
|
||||||
Num(17),
|
Num(2),
|
||||||
Str("units"),
|
Bool(true),
|
||||||
Num(0))))
|
Num(17),
|
||||||
|
Str("units"),
|
||||||
|
Num(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(responseAs[
|
assert(
|
||||||
String] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""")
|
responseAs[
|
||||||
|
String
|
||||||
|
] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,12 +356,16 @@ class OracleRoutesSpec
|
|||||||
|
|
||||||
val route =
|
val route =
|
||||||
oracleRoutes.handleCommand(
|
oracleRoutes.handleCommand(
|
||||||
ServerCommand("signenum", Arr(Str("id"), Str("outcome"))))
|
ServerCommand("signenum", Arr(Str("id"), Str("outcome")))
|
||||||
|
)
|
||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(responseAs[
|
assert(
|
||||||
String] == s"""{"result":"${dummyAttestmentTLV.hex}","error":null}""")
|
responseAs[
|
||||||
|
String
|
||||||
|
] == s"""{"result":"${dummyAttestmentTLV.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,12 +377,16 @@ class OracleRoutesSpec
|
|||||||
|
|
||||||
val route =
|
val route =
|
||||||
oracleRoutes.handleCommand(
|
oracleRoutes.handleCommand(
|
||||||
ServerCommand("signdigits", Arr(Str("id"), Num(123))))
|
ServerCommand("signdigits", Arr(Str("id"), Num(123)))
|
||||||
|
)
|
||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(responseAs[
|
assert(
|
||||||
String] == s"""{"result":"${dummyAttestmentTLV.hex}","error":null}""")
|
responseAs[
|
||||||
|
String
|
||||||
|
] == s"""{"result":"${dummyAttestmentTLV.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,12 +398,16 @@ class OracleRoutesSpec
|
|||||||
|
|
||||||
val route =
|
val route =
|
||||||
oracleRoutes.handleCommand(
|
oracleRoutes.handleCommand(
|
||||||
ServerCommand("getsignatures", Arr(Str("id"))))
|
ServerCommand("getsignatures", Arr(Str("id")))
|
||||||
|
)
|
||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(responseAs[
|
assert(
|
||||||
String] == s"""{"result":"${dummyAttestmentTLV.hex}","error":null}""")
|
responseAs[
|
||||||
|
String
|
||||||
|
] == s"""{"result":"${dummyAttestmentTLV.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,12 +419,14 @@ class OracleRoutesSpec
|
|||||||
|
|
||||||
val route =
|
val route =
|
||||||
oracleRoutes.handleCommand(
|
oracleRoutes.handleCommand(
|
||||||
ServerCommand("signmessage", Arr(Str("message"))))
|
ServerCommand("signmessage", Arr(Str("message")))
|
||||||
|
)
|
||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(
|
assert(
|
||||||
responseAs[String] == s"""{"result":"${sig.hex}","error":null}""")
|
responseAs[String] == s"""{"result":"${sig.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,8 +441,11 @@ class OracleRoutesSpec
|
|||||||
val route = oracleRoutes.handleCommand(cmd)
|
val route = oracleRoutes.handleCommand(cmd)
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(responseAs[
|
assert(
|
||||||
String] == s"""{"result":"${dummyOracleEvent.announcementTLV.hex}","error":null}""")
|
responseAs[
|
||||||
|
String
|
||||||
|
] == s"""{"result":"${dummyOracleEvent.announcementTLV.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,8 +461,11 @@ class OracleRoutesSpec
|
|||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(responseAs[
|
assert(
|
||||||
String] == s"""{"result":"${dummyOracleEvent.announcementTLV.hex}","error":null}""")
|
responseAs[
|
||||||
|
String
|
||||||
|
] == s"""{"result":"${dummyOracleEvent.announcementTLV.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,7 +480,8 @@ class OracleRoutesSpec
|
|||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(
|
assert(
|
||||||
responseAs[String] == s"""{"result":"oracle name","error":null}""")
|
responseAs[String] == s"""{"result":"oracle name","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,12 +493,14 @@ class OracleRoutesSpec
|
|||||||
|
|
||||||
val route =
|
val route =
|
||||||
oracleRoutes.handleCommand(
|
oracleRoutes.handleCommand(
|
||||||
ServerCommand("setoraclename", Arr(Str("oracle name"))))
|
ServerCommand("setoraclename", Arr(Str("oracle name")))
|
||||||
|
)
|
||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(
|
assert(
|
||||||
responseAs[String] == s"""{"result":"oracle name","error":null}""")
|
responseAs[String] == s"""{"result":"oracle name","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ import scala.util.{Failure, Success}
|
|||||||
|
|
||||||
case class OracleRoutes(oracle: DLCOracleApi)(implicit
|
case class OracleRoutes(oracle: DLCOracleApi)(implicit
|
||||||
system: ActorSystem,
|
system: ActorSystem,
|
||||||
conf: DLCOracleAppConfig)
|
conf: DLCOracleAppConfig
|
||||||
extends ServerRoute {
|
) extends ServerRoute {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
|
|
||||||
override def handleCommand: PartialFunction[ServerCommand, StandardRoute] = {
|
override def handleCommand: PartialFunction[ServerCommand, StandardRoute] = {
|
||||||
@ -71,12 +71,15 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit
|
|||||||
case Failure(exception) =>
|
case Failure(exception) =>
|
||||||
reject(ValidationRejection("failure", Some(exception)))
|
reject(ValidationRejection("failure", Some(exception)))
|
||||||
case Success(
|
case Success(
|
||||||
CreateNumericAnnouncement(eventName,
|
CreateNumericAnnouncement(
|
||||||
maturationTime,
|
eventName,
|
||||||
minValue,
|
maturationTime,
|
||||||
maxValue,
|
minValue,
|
||||||
unit,
|
maxValue,
|
||||||
precision)) =>
|
unit,
|
||||||
|
precision
|
||||||
|
)
|
||||||
|
) =>
|
||||||
complete {
|
complete {
|
||||||
|
|
||||||
val isSigned = minValue < 0
|
val isSigned = minValue < 0
|
||||||
@ -84,13 +87,15 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit
|
|||||||
Math.ceil(Math.log(maxValue.toDouble) / Math.log(2)).toInt
|
Math.ceil(Math.log(maxValue.toDouble) / Math.log(2)).toInt
|
||||||
|
|
||||||
oracle
|
oracle
|
||||||
.createNewDigitDecompAnnouncement(eventName,
|
.createNewDigitDecompAnnouncement(
|
||||||
maturationTime,
|
eventName,
|
||||||
UInt16(2),
|
maturationTime,
|
||||||
isSigned,
|
UInt16(2),
|
||||||
numDigits,
|
isSigned,
|
||||||
unit,
|
numDigits,
|
||||||
Int32(precision))
|
unit,
|
||||||
|
Int32(precision)
|
||||||
|
)
|
||||||
.map { announcementTLV =>
|
.map { announcementTLV =>
|
||||||
Server.httpSuccess(announcementTLV.hex)
|
Server.httpSuccess(announcementTLV.hex)
|
||||||
}
|
}
|
||||||
@ -105,22 +110,27 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit
|
|||||||
case Failure(exception) =>
|
case Failure(exception) =>
|
||||||
reject(ValidationRejection("failure", Some(exception)))
|
reject(ValidationRejection("failure", Some(exception)))
|
||||||
case Success(
|
case Success(
|
||||||
CreateDigitDecompAnnouncement(eventName,
|
CreateDigitDecompAnnouncement(
|
||||||
maturationTime,
|
eventName,
|
||||||
base,
|
maturationTime,
|
||||||
isSigned,
|
base,
|
||||||
numDigits,
|
isSigned,
|
||||||
unit,
|
numDigits,
|
||||||
precision)) =>
|
unit,
|
||||||
|
precision
|
||||||
|
)
|
||||||
|
) =>
|
||||||
complete {
|
complete {
|
||||||
oracle
|
oracle
|
||||||
.createNewDigitDecompAnnouncement(eventName,
|
.createNewDigitDecompAnnouncement(
|
||||||
maturationTime,
|
eventName,
|
||||||
UInt16(base),
|
maturationTime,
|
||||||
isSigned,
|
UInt16(base),
|
||||||
numDigits,
|
isSigned,
|
||||||
unit,
|
numDigits,
|
||||||
Int32(precision))
|
unit,
|
||||||
|
Int32(precision)
|
||||||
|
)
|
||||||
.map { announcementTLV =>
|
.map { announcementTLV =>
|
||||||
Server.httpSuccess(announcementTLV.hex)
|
Server.httpSuccess(announcementTLV.hex)
|
||||||
}
|
}
|
||||||
@ -179,9 +189,11 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit
|
|||||||
"signingVersion" -> Str(event.signingVersion.toString),
|
"signingVersion" -> Str(event.signingVersion.toString),
|
||||||
"maturationTime" -> Str(event.maturationTime.toString),
|
"maturationTime" -> Str(event.maturationTime.toString),
|
||||||
"maturationTimeEpoch" -> Num(
|
"maturationTimeEpoch" -> Num(
|
||||||
event.maturationTime.getEpochSecond.toDouble),
|
event.maturationTime.getEpochSecond.toDouble
|
||||||
|
),
|
||||||
"announcementSignature" -> Str(
|
"announcementSignature" -> Str(
|
||||||
event.announcementSignature.hex),
|
event.announcementSignature.hex
|
||||||
|
),
|
||||||
"eventDescriptorTLV" -> Str(event.eventDescriptorTLV.hex),
|
"eventDescriptorTLV" -> Str(event.eventDescriptorTLV.hex),
|
||||||
"eventTLV" -> Str(event.eventTLV.hex),
|
"eventTLV" -> Str(event.eventTLV.hex),
|
||||||
"announcementTLV" -> Str(event.announcementTLV.hex),
|
"announcementTLV" -> Str(event.announcementTLV.hex),
|
||||||
@ -269,9 +281,11 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit
|
|||||||
case Success(KeyManagerPassphraseChange(oldPassword, newPassword)) =>
|
case Success(KeyManagerPassphraseChange(oldPassword, newPassword)) =>
|
||||||
complete {
|
complete {
|
||||||
val path = conf.seedPath
|
val path = conf.seedPath
|
||||||
WalletStorage.changeAesPassword(path,
|
WalletStorage.changeAesPassword(
|
||||||
Some(oldPassword),
|
path,
|
||||||
Some(newPassword))
|
Some(oldPassword),
|
||||||
|
Some(newPassword)
|
||||||
|
)
|
||||||
|
|
||||||
Server.httpSuccess(ujson.Null)
|
Server.httpSuccess(ujson.Null)
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,8 @@ import scala.concurrent.{Await, Future}
|
|||||||
|
|
||||||
class OracleServerMain(override val serverArgParser: ServerArgParser)(implicit
|
class OracleServerMain(override val serverArgParser: ServerArgParser)(implicit
|
||||||
override val system: ActorSystem,
|
override val system: ActorSystem,
|
||||||
conf: DLCOracleAppConfig)
|
conf: DLCOracleAppConfig
|
||||||
extends BitcoinSServerRunner[Unit] {
|
) extends BitcoinSServerRunner[Unit] {
|
||||||
|
|
||||||
override def start(): Future[Unit] = {
|
override def start(): Future[Unit] = {
|
||||||
|
|
||||||
@ -31,21 +31,25 @@ class OracleServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
routes = Seq(OracleRoutes(oracle), commonRoutes).map(Future.successful)
|
routes = Seq(OracleRoutes(oracle), commonRoutes).map(Future.successful)
|
||||||
server = serverArgParser.rpcPortOpt match {
|
server = serverArgParser.rpcPortOpt match {
|
||||||
case Some(rpcport) =>
|
case Some(rpcport) =>
|
||||||
Server(conf = conf,
|
Server(
|
||||||
handlersF = routes,
|
conf = conf,
|
||||||
rpcbindOpt = bindConfOpt,
|
handlersF = routes,
|
||||||
rpcport = rpcport,
|
rpcbindOpt = bindConfOpt,
|
||||||
rpcPassword = conf.rpcPassword,
|
rpcport = rpcport,
|
||||||
None,
|
rpcPassword = conf.rpcPassword,
|
||||||
Source.empty)
|
None,
|
||||||
|
Source.empty
|
||||||
|
)
|
||||||
case None =>
|
case None =>
|
||||||
Server(conf = conf,
|
Server(
|
||||||
handlersF = routes,
|
conf = conf,
|
||||||
rpcbindOpt = bindConfOpt,
|
handlersF = routes,
|
||||||
rpcport = conf.rpcPort,
|
rpcbindOpt = bindConfOpt,
|
||||||
rpcPassword = conf.rpcPassword,
|
rpcport = conf.rpcPort,
|
||||||
None,
|
rpcPassword = conf.rpcPassword,
|
||||||
Source.empty)
|
None,
|
||||||
|
Source.empty
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindings <- server.start()
|
bindings <- server.start()
|
||||||
@ -88,14 +92,16 @@ object OracleServerMain extends BitcoinSAppScalaDaemon {
|
|||||||
|
|
||||||
implicit lazy val conf: DLCOracleAppConfig =
|
implicit lazy val conf: DLCOracleAppConfig =
|
||||||
DLCOracleAppConfig(datadirParser.datadir, Vector(datadirParser.baseConfig))(
|
DLCOracleAppConfig(datadirParser.datadir, Vector(datadirParser.baseConfig))(
|
||||||
system.dispatcher)
|
system.dispatcher
|
||||||
|
)
|
||||||
|
|
||||||
val m = new OracleServerMain(serverCmdLineArgs)
|
val m = new OracleServerMain(serverCmdLineArgs)
|
||||||
m.run()
|
m.run()
|
||||||
|
|
||||||
sys.addShutdownHook {
|
sys.addShutdownHook {
|
||||||
logger.info(
|
logger.info(
|
||||||
s"@@@@@@@@@@@@@@@@@@@@@ Shutting down ${getClass.getSimpleName} @@@@@@@@@@@@@@@@@@@@@")
|
s"@@@@@@@@@@@@@@@@@@@@@ Shutting down ${getClass.getSimpleName} @@@@@@@@@@@@@@@@@@@@@"
|
||||||
|
)
|
||||||
Await.result(m.stop(), 10.seconds)
|
Await.result(m.stop(), 10.seconds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,9 @@ object SignMessage extends ServerJsonModels {
|
|||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length}. Expected: 1"))
|
s"Bad number of arguments: ${other.length}. Expected: 1"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,7 +40,8 @@ object SignMessage extends ServerJsonModels {
|
|||||||
case class CreateAnnouncement(
|
case class CreateAnnouncement(
|
||||||
label: String,
|
label: String,
|
||||||
maturationTime: Instant,
|
maturationTime: Instant,
|
||||||
outcomes: Vector[String])
|
outcomes: Vector[String]
|
||||||
|
)
|
||||||
|
|
||||||
object CreateAnnouncement extends ServerJsonModels {
|
object CreateAnnouncement extends ServerJsonModels {
|
||||||
|
|
||||||
@ -54,11 +57,14 @@ object CreateAnnouncement extends ServerJsonModels {
|
|||||||
}
|
}
|
||||||
case Nil =>
|
case Nil =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException("Missing label and outcome arguments"))
|
new IllegalArgumentException("Missing label and outcome arguments")
|
||||||
|
)
|
||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
s"Bad number of arguments: ${other.length}. Expected: 2"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,7 +75,8 @@ case class CreateNumericAnnouncement(
|
|||||||
minValue: Long,
|
minValue: Long,
|
||||||
maxValue: Long,
|
maxValue: Long,
|
||||||
unit: String,
|
unit: String,
|
||||||
precision: Int)
|
precision: Int
|
||||||
|
)
|
||||||
|
|
||||||
object CreateNumericAnnouncement extends ServerJsonModels {
|
object CreateNumericAnnouncement extends ServerJsonModels {
|
||||||
|
|
||||||
@ -84,20 +91,27 @@ object CreateNumericAnnouncement extends ServerJsonModels {
|
|||||||
val unit = unitJs.str
|
val unit = unitJs.str
|
||||||
val precision = precisionJs.num.toInt
|
val precision = precisionJs.num.toInt
|
||||||
|
|
||||||
CreateNumericAnnouncement(label,
|
CreateNumericAnnouncement(
|
||||||
maturationTime,
|
label,
|
||||||
minValue,
|
maturationTime,
|
||||||
maxValue,
|
minValue,
|
||||||
unit,
|
maxValue,
|
||||||
precision)
|
unit,
|
||||||
|
precision
|
||||||
|
)
|
||||||
}
|
}
|
||||||
case Nil =>
|
case Nil =>
|
||||||
Failure(new IllegalArgumentException(
|
Failure(
|
||||||
"Missing label, maturationTime, minValue, maxValue, units, and precision arguments"))
|
new IllegalArgumentException(
|
||||||
|
"Missing label, maturationTime, minValue, maxValue, units, and precision arguments"
|
||||||
|
)
|
||||||
|
)
|
||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length}. Expected: 6"))
|
s"Bad number of arguments: ${other.length}. Expected: 6"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,7 +123,8 @@ case class CreateDigitDecompAnnouncement(
|
|||||||
isSigned: Boolean,
|
isSigned: Boolean,
|
||||||
numDigits: Int,
|
numDigits: Int,
|
||||||
unit: String,
|
unit: String,
|
||||||
precision: Int)
|
precision: Int
|
||||||
|
)
|
||||||
|
|
||||||
object CreateDigitDecompAnnouncement extends ServerJsonModels {
|
object CreateDigitDecompAnnouncement extends ServerJsonModels {
|
||||||
|
|
||||||
@ -126,21 +141,28 @@ object CreateDigitDecompAnnouncement extends ServerJsonModels {
|
|||||||
val unit = unitJs.str
|
val unit = unitJs.str
|
||||||
val precision = precisionJs.num.toInt
|
val precision = precisionJs.num.toInt
|
||||||
|
|
||||||
CreateDigitDecompAnnouncement(label,
|
CreateDigitDecompAnnouncement(
|
||||||
maturationTime,
|
label,
|
||||||
base,
|
maturationTime,
|
||||||
isSigned,
|
base,
|
||||||
numDigits,
|
isSigned,
|
||||||
unit,
|
numDigits,
|
||||||
precision)
|
unit,
|
||||||
|
precision
|
||||||
|
)
|
||||||
}
|
}
|
||||||
case Nil =>
|
case Nil =>
|
||||||
Failure(new IllegalArgumentException(
|
Failure(
|
||||||
"Missing label, maturationTime, base, isSigned, numDigits, units, and precision arguments"))
|
new IllegalArgumentException(
|
||||||
|
"Missing label, maturationTime, base, isSigned, numDigits, units, and precision arguments"
|
||||||
|
)
|
||||||
|
)
|
||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length}. Expected: 7"))
|
s"Bad number of arguments: ${other.length}. Expected: 7"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,11 +182,15 @@ object SignEnum extends ServerJsonModels {
|
|||||||
case Nil =>
|
case Nil =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
"Missing oracle event tlv and outcome arguments"))
|
"Missing oracle event tlv and outcome arguments"
|
||||||
|
)
|
||||||
|
)
|
||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
s"Bad number of arguments: ${other.length}. Expected: 2"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,7 +208,8 @@ object SignDigits extends ServerJsonModels {
|
|||||||
case str: Str => str.value.toDouble
|
case str: Str => str.value.toDouble
|
||||||
case _: Value =>
|
case _: Value =>
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
s"Unable to parse $numJs as a number")
|
s"Unable to parse $numJs as a number"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
SignDigits(nameJs.str, num.toLong)
|
SignDigits(nameJs.str, num.toLong)
|
||||||
@ -190,11 +217,15 @@ object SignDigits extends ServerJsonModels {
|
|||||||
case Nil =>
|
case Nil =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
"Missing oracle event tlv and num arguments"))
|
"Missing oracle event tlv and num arguments"
|
||||||
|
)
|
||||||
|
)
|
||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
s"Bad number of arguments: ${other.length}. Expected: 2"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,8 +235,10 @@ case class GetAnnouncement(eventName: String)
|
|||||||
object GetAnnouncement extends ServerJsonModels {
|
object GetAnnouncement extends ServerJsonModels {
|
||||||
|
|
||||||
def fromJsArr(jsArr: ujson.Arr): Try[GetAnnouncement] = {
|
def fromJsArr(jsArr: ujson.Arr): Try[GetAnnouncement] = {
|
||||||
require(jsArr.arr.size == 1,
|
require(
|
||||||
s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1")
|
jsArr.arr.size == 1,
|
||||||
|
s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1"
|
||||||
|
)
|
||||||
Try {
|
Try {
|
||||||
GetAnnouncement(jsArr.arr.head.str)
|
GetAnnouncement(jsArr.arr.head.str)
|
||||||
}
|
}
|
||||||
@ -214,7 +247,8 @@ object GetAnnouncement extends ServerJsonModels {
|
|||||||
|
|
||||||
case class KeyManagerPassphraseChange(
|
case class KeyManagerPassphraseChange(
|
||||||
oldPassword: AesPassword,
|
oldPassword: AesPassword,
|
||||||
newPassword: AesPassword)
|
newPassword: AesPassword
|
||||||
|
)
|
||||||
|
|
||||||
object KeyManagerPassphraseChange extends ServerJsonModels {
|
object KeyManagerPassphraseChange extends ServerJsonModels {
|
||||||
|
|
||||||
@ -230,11 +264,15 @@ object KeyManagerPassphraseChange extends ServerJsonModels {
|
|||||||
case Nil =>
|
case Nil =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
"Missing old password and new password arguments"))
|
"Missing old password and new password arguments"
|
||||||
|
)
|
||||||
|
)
|
||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
s"Bad number of arguments: ${other.length}. Expected: 2"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,7 +294,9 @@ object KeyManagerPassphraseSet extends ServerJsonModels {
|
|||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length}. Expected: 1"))
|
s"Bad number of arguments: ${other.length}. Expected: 1"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,8 +316,11 @@ object DeleteAnnouncement
|
|||||||
case Vector() =>
|
case Vector() =>
|
||||||
Failure(new IllegalArgumentException(s"Missing event name argument"))
|
Failure(new IllegalArgumentException(s"Missing event name argument"))
|
||||||
case other =>
|
case other =>
|
||||||
Failure(new IllegalArgumentException(
|
Failure(
|
||||||
s"Bad number of arguments to deleteannouncement, got=${other.length} expected: 1"))
|
new IllegalArgumentException(
|
||||||
|
s"Bad number of arguments to deleteannouncement, got=${other.length} expected: 1"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,7 +346,9 @@ object DeleteAttestation
|
|||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length}. Expected: 1"))
|
s"Bad number of arguments: ${other.length}. Expected: 1"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,7 +386,8 @@ trait ServerJsonModels {
|
|||||||
LockUnspentOutputParameter.fromJson(js)
|
LockUnspentOutputParameter.fromJson(js)
|
||||||
|
|
||||||
def jsToLockUnspentOutputParameters(
|
def jsToLockUnspentOutputParameters(
|
||||||
js: Value): Seq[LockUnspentOutputParameter] = {
|
js: Value
|
||||||
|
): Seq[LockUnspentOutputParameter] = {
|
||||||
js.arr.foldLeft(Seq.empty[LockUnspentOutputParameter])((seq, outPoint) =>
|
js.arr.foldLeft(Seq.empty[LockUnspentOutputParameter])((seq, outPoint) =>
|
||||||
seq :+ jsToLockUnspentOutputParameter(outPoint))
|
seq :+ jsToLockUnspentOutputParameter(outPoint))
|
||||||
}
|
}
|
||||||
|
@ -16,15 +16,16 @@ import org.bitcoins.server.util.BitcoinSAppScalaDaemon
|
|||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
|
|
||||||
/** Useful script for scanning bitcoind
|
/** Useful script for scanning bitcoind This file assumes you have
|
||||||
* This file assumes you have pre-configured the connection
|
* pre-configured the connection between bitcoin-s and bitcoind inside of
|
||||||
* between bitcoin-s and bitcoind inside of bitcoin-s.conf
|
* bitcoin-s.conf
|
||||||
* @see https://bitcoin-s.org/docs/config/configuration#example-configuration-file
|
* @see
|
||||||
|
* https://bitcoin-s.org/docs/config/configuration#example-configuration-file
|
||||||
*/
|
*/
|
||||||
class ScanBitcoind()(implicit
|
class ScanBitcoind()(implicit
|
||||||
override val system: ActorSystem,
|
override val system: ActorSystem,
|
||||||
rpcAppConfig: BitcoindRpcAppConfig)
|
rpcAppConfig: BitcoindRpcAppConfig
|
||||||
extends BitcoinSRunner[Unit] {
|
) extends BitcoinSRunner[Unit] {
|
||||||
|
|
||||||
override def start(): Future[Unit] = {
|
override def start(): Future[Unit] = {
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ class ScanBitcoind()(implicit
|
|||||||
val f = for {
|
val f = for {
|
||||||
bitcoind <- bitcoindF
|
bitcoind <- bitcoindF
|
||||||
endHeight <- endHeightF
|
endHeight <- endHeightF
|
||||||
//_ <- countWitV1MempoolTxs(bitcoind)
|
// _ <- countWitV1MempoolTxs(bitcoind)
|
||||||
_ <- countTaprootTxsInBlocks(endHeight, 50000, bitcoind)
|
_ <- countTaprootTxsInBlocks(endHeight, 50000, bitcoind)
|
||||||
} yield ()
|
} yield ()
|
||||||
f.failed.foreach(err =>
|
f.failed.foreach(err =>
|
||||||
@ -50,13 +51,15 @@ class ScanBitcoind()(implicit
|
|||||||
.map(_ => ())
|
.map(_ => ())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Searches a given Source[Int] that represents block heights applying f to them and returning a Seq[T] with the results */
|
/** Searches a given Source[Int] that represents block heights applying f to
|
||||||
|
* them and returning a Seq[T] with the results
|
||||||
|
*/
|
||||||
def searchBlocks[T](
|
def searchBlocks[T](
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
source: Source[Int, NotUsed],
|
source: Source[Int, NotUsed],
|
||||||
f: Block => T,
|
f: Block => T,
|
||||||
numParallelism: Int = Runtime.getRuntime.availableProcessors()): Future[
|
numParallelism: Int = Runtime.getRuntime.availableProcessors()
|
||||||
Seq[T]] = {
|
): Future[Seq[T]] = {
|
||||||
source
|
source
|
||||||
.mapAsync(parallelism = numParallelism) { height =>
|
.mapAsync(parallelism = numParallelism) { height =>
|
||||||
bitcoind
|
bitcoind
|
||||||
@ -66,7 +69,8 @@ class ScanBitcoind()(implicit
|
|||||||
}
|
}
|
||||||
.mapAsync(numParallelism) { case (block, height) =>
|
.mapAsync(numParallelism) { case (block, height) =>
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Searching block at height=$height hashBE=${block.blockHeader.hashBE.hex}")
|
s"Searching block at height=$height hashBE=${block.blockHeader.hashBE.hex}"
|
||||||
|
)
|
||||||
FutureUtil.makeAsync { () =>
|
FutureUtil.makeAsync { () =>
|
||||||
f(block)
|
f(block)
|
||||||
}
|
}
|
||||||
@ -78,11 +82,12 @@ class ScanBitcoind()(implicit
|
|||||||
def countSegwitTxs(
|
def countSegwitTxs(
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
startHeight: Int,
|
startHeight: Int,
|
||||||
endHeight: Int): Future[Unit] = {
|
endHeight: Int
|
||||||
|
): Future[Unit] = {
|
||||||
val startTime = System.currentTimeMillis()
|
val startTime = System.currentTimeMillis()
|
||||||
val source: Source[Int, NotUsed] = Source(startHeight.to(endHeight))
|
val source: Source[Int, NotUsed] = Source(startHeight.to(endHeight))
|
||||||
|
|
||||||
//in this simple example, we are going to count the number of witness transactions
|
// in this simple example, we are going to count the number of witness transactions
|
||||||
val countSegwitTxs: Block => Int = { block: Block =>
|
val countSegwitTxs: Block => Int = { block: Block =>
|
||||||
block.transactions.count(_.isInstanceOf[WitnessTransaction])
|
block.transactions.count(_.isInstanceOf[WitnessTransaction])
|
||||||
}
|
}
|
||||||
@ -96,14 +101,16 @@ class ScanBitcoind()(implicit
|
|||||||
count <- countF
|
count <- countF
|
||||||
endTime = System.currentTimeMillis()
|
endTime = System.currentTimeMillis()
|
||||||
_ = logger.info(
|
_ = logger.info(
|
||||||
s"Count of segwit txs from height=${startHeight} to endHeight=${endHeight} is ${count}. It took ${endTime - startTime}ms ")
|
s"Count of segwit txs from height=${startHeight} to endHeight=${endHeight} is ${count}. It took ${endTime - startTime}ms "
|
||||||
|
)
|
||||||
} yield ()
|
} yield ()
|
||||||
}
|
}
|
||||||
|
|
||||||
def countTaprootTxsInBlocks(
|
def countTaprootTxsInBlocks(
|
||||||
endHeight: Int,
|
endHeight: Int,
|
||||||
lastBlocks: Int,
|
lastBlocks: Int,
|
||||||
bitcoind: BitcoindRpcClient): Future[Int] = {
|
bitcoind: BitcoindRpcClient
|
||||||
|
): Future[Int] = {
|
||||||
val startTime = System.currentTimeMillis()
|
val startTime = System.currentTimeMillis()
|
||||||
val startHeight = endHeight - lastBlocks
|
val startHeight = endHeight - lastBlocks
|
||||||
val source: Source[Int, NotUsed] = Source(startHeight.to(endHeight))
|
val source: Source[Int, NotUsed] = Source(startHeight.to(endHeight))
|
||||||
@ -124,7 +131,8 @@ class ScanBitcoind()(implicit
|
|||||||
count <- countF
|
count <- countF
|
||||||
endTime = System.currentTimeMillis()
|
endTime = System.currentTimeMillis()
|
||||||
_ = logger.info(
|
_ = logger.info(
|
||||||
s"Count of taproot outputs from height=${startHeight} to endHeight=${endHeight} is ${count}. It took ${endTime - startTime}ms ")
|
s"Count of taproot outputs from height=${startHeight} to endHeight=${endHeight} is ${count}. It took ${endTime - startTime}ms "
|
||||||
|
)
|
||||||
} yield count
|
} yield count
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,12 +143,14 @@ class ScanBitcoind()(implicit
|
|||||||
})
|
})
|
||||||
countF.foreach(c =>
|
countF.foreach(c =>
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Found $c mempool transactions with witness v1 outputs at ${Instant.now}"))
|
s"Found $c mempool transactions with witness v1 outputs at ${Instant.now}"
|
||||||
|
))
|
||||||
countF
|
countF
|
||||||
}
|
}
|
||||||
|
|
||||||
def getMemPoolSource(
|
def getMemPoolSource(
|
||||||
bitcoind: BitcoindRpcClient): Future[Source[Transaction, NotUsed]] = {
|
bitcoind: BitcoindRpcClient
|
||||||
|
): Future[Source[Transaction, NotUsed]] = {
|
||||||
val mempoolF = bitcoind.getRawMemPool
|
val mempoolF = bitcoind.getRawMemPool
|
||||||
val sourceF: Future[Source[DoubleSha256DigestBE, NotUsed]] =
|
val sourceF: Future[Source[DoubleSha256DigestBE, NotUsed]] =
|
||||||
mempoolF.map(Source(_))
|
mempoolF.map(Source(_))
|
||||||
|
@ -10,15 +10,17 @@ import org.bitcoins.server.util.BitcoinSAppScalaDaemon
|
|||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
|
|
||||||
/** This script zips your $HOME/.bitcoin-s/ directory to a specified path, excluding chaindb.sqlite */
|
/** This script zips your $HOME/.bitcoin-s/ directory to a specified path,
|
||||||
|
* excluding chaindb.sqlite
|
||||||
|
*/
|
||||||
class ZipDatadir(override val serverArgParser: ServerArgParser)(implicit
|
class ZipDatadir(override val serverArgParser: ServerArgParser)(implicit
|
||||||
override val system: ActorSystem,
|
override val system: ActorSystem,
|
||||||
conf: BitcoinSAppConfig)
|
conf: BitcoinSAppConfig
|
||||||
extends BitcoinSServerRunner[Unit] {
|
) extends BitcoinSServerRunner[Unit] {
|
||||||
|
|
||||||
override def start(): Future[Unit] = {
|
override def start(): Future[Unit] = {
|
||||||
|
|
||||||
//replace the line below with where you want to zip too
|
// replace the line below with where you want to zip too
|
||||||
val path = Paths.get("/tmp", "bitcoin-s.zip")
|
val path = Paths.get("/tmp", "bitcoin-s.zip")
|
||||||
val target = DatadirUtil.zipDatadir(conf.baseDatadir, path)
|
val target = DatadirUtil.zipDatadir(conf.baseDatadir, path)
|
||||||
logger.info(s"Done zipping to $target!")
|
logger.info(s"Done zipping to $target!")
|
||||||
@ -46,7 +48,8 @@ object Zip extends BitcoinSAppScalaDaemon {
|
|||||||
|
|
||||||
implicit lazy val conf: BitcoinSAppConfig =
|
implicit lazy val conf: BitcoinSAppConfig =
|
||||||
BitcoinSAppConfig(datadirParser.datadir, Vector(datadirParser.baseConfig))(
|
BitcoinSAppConfig(datadirParser.datadir, Vector(datadirParser.baseConfig))(
|
||||||
system)
|
system
|
||||||
|
)
|
||||||
|
|
||||||
new ZipDatadir(serverCmdLineArgs).run()
|
new ZipDatadir(serverCmdLineArgs).run()
|
||||||
}
|
}
|
||||||
|
@ -31,11 +31,13 @@ import upickle.default.{read, write, Reader, Writer}
|
|||||||
|
|
||||||
import scala.collection.immutable.Seq
|
import scala.collection.immutable.Seq
|
||||||
|
|
||||||
/** Automatic to and from JSON marshalling/unmarshalling using *upickle* protocol.
|
/** Automatic to and from JSON marshalling/unmarshalling using *upickle*
|
||||||
|
* protocol.
|
||||||
*/
|
*/
|
||||||
object UpickleSupport extends UpickleSupport
|
object UpickleSupport extends UpickleSupport
|
||||||
|
|
||||||
/** Automatic to and from JSON marshalling/unmarshalling using *upickle* protocol.
|
/** Automatic to and from JSON marshalling/unmarshalling using *upickle*
|
||||||
|
* protocol.
|
||||||
*/
|
*/
|
||||||
trait UpickleSupport {
|
trait UpickleSupport {
|
||||||
|
|
||||||
@ -58,16 +60,20 @@ trait UpickleSupport {
|
|||||||
|
|
||||||
/** HTTP entity => `A`
|
/** HTTP entity => `A`
|
||||||
*
|
*
|
||||||
* @tparam A type to decode
|
* @tparam A
|
||||||
* @return unmarshaller for `A`
|
* type to decode
|
||||||
|
* @return
|
||||||
|
* unmarshaller for `A`
|
||||||
*/
|
*/
|
||||||
implicit def unmarshaller[A: Reader]: FromEntityUnmarshaller[A] =
|
implicit def unmarshaller[A: Reader]: FromEntityUnmarshaller[A] =
|
||||||
jsonStringUnmarshaller.map(read(_))
|
jsonStringUnmarshaller.map(read(_))
|
||||||
|
|
||||||
/** `A` => HTTP entity
|
/** `A` => HTTP entity
|
||||||
*
|
*
|
||||||
* @tparam A type to encode
|
* @tparam A
|
||||||
* @return marshaller for any `A` value
|
* type to encode
|
||||||
|
* @return
|
||||||
|
* marshaller for any `A` value
|
||||||
*/
|
*/
|
||||||
implicit def marshaller[A: Writer]: ToEntityMarshaller[A] =
|
implicit def marshaller[A: Writer]: ToEntityMarshaller[A] =
|
||||||
jsonStringMarshaller.compose(write(_))
|
jsonStringMarshaller.compose(write(_))
|
||||||
|
@ -15,16 +15,17 @@ trait BitcoinSRunner[T] extends StartStopAsync[T] with BitcoinSLogger {
|
|||||||
// start everything!
|
// start everything!
|
||||||
final def run(): Future[T] = {
|
final def run(): Future[T] = {
|
||||||
|
|
||||||
//We need to set the system property before any logger instances
|
// We need to set the system property before any logger instances
|
||||||
//are in instantiated. If we don't do this, we will not log to
|
// are in instantiated. If we don't do this, we will not log to
|
||||||
//the correct location
|
// the correct location
|
||||||
//see: https://github.com/bitcoin-s/bitcoin-s/issues/2496
|
// see: https://github.com/bitcoin-s/bitcoin-s/issues/2496
|
||||||
//System.setProperty("bitcoins.log.location", usedDir.toAbsolutePath.toString)
|
// System.setProperty("bitcoins.log.location", usedDir.toAbsolutePath.toString)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
s"version=${EnvUtil.getVersion} jdkVersion=${EnvUtil.getJdkVersion}")
|
s"version=${EnvUtil.getVersion} jdkVersion=${EnvUtil.getJdkVersion}"
|
||||||
|
)
|
||||||
|
|
||||||
//logger.info(s"using directory ${usedDir.toAbsolutePath.toString}")
|
// logger.info(s"using directory ${usedDir.toAbsolutePath.toString}")
|
||||||
val runner: Future[T] = start()
|
val runner: Future[T] = start()
|
||||||
runner.failed.foreach { err =>
|
runner.failed.foreach { err =>
|
||||||
logger.error(s"Failed to startup server!", err)
|
logger.error(s"Failed to startup server!", err)
|
||||||
|
@ -8,28 +8,33 @@ import org.apache.pekko.http.scaladsl.server.Directives._
|
|||||||
import org.apache.pekko.http.scaladsl.server.Route
|
import org.apache.pekko.http.scaladsl.server.Route
|
||||||
|
|
||||||
/** Add CORS handling for accessing backend over localhost from modern browsers
|
/** Add CORS handling for accessing backend over localhost from modern browsers
|
||||||
* @see dzone.com/articles/handling-cors-in-akka-http
|
* @see
|
||||||
|
* dzone.com/articles/handling-cors-in-akka-http
|
||||||
*/
|
*/
|
||||||
trait CORSHandler {
|
trait CORSHandler {
|
||||||
|
|
||||||
private val corsResponseHeaders = List(
|
private val corsResponseHeaders = List(
|
||||||
`Access-Control-Allow-Origin`.*,
|
`Access-Control-Allow-Origin`.*,
|
||||||
`Access-Control-Allow-Credentials`(true),
|
`Access-Control-Allow-Credentials`(true),
|
||||||
`Access-Control-Allow-Headers`("Authorization",
|
`Access-Control-Allow-Headers`(
|
||||||
"Content-Type",
|
"Authorization",
|
||||||
"X-Requested-With")
|
"Content-Type",
|
||||||
|
"X-Requested-With"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
//this directive adds access control headers to normal responses
|
// this directive adds access control headers to normal responses
|
||||||
private def addAccessControlHeaders: Directive0 = {
|
private def addAccessControlHeaders: Directive0 = {
|
||||||
respondWithHeaders(corsResponseHeaders)
|
respondWithHeaders(corsResponseHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
//this handles preflight OPTIONS requests.
|
// this handles preflight OPTIONS requests.
|
||||||
private def preflightRequestHandler: Route = options {
|
private def preflightRequestHandler: Route = options {
|
||||||
complete(
|
complete(
|
||||||
HttpResponse(StatusCodes.OK).withHeaders(
|
HttpResponse(StatusCodes.OK).withHeaders(
|
||||||
`Access-Control-Allow-Methods`(OPTIONS, POST, PUT, GET, DELETE)))
|
`Access-Control-Allow-Methods`(OPTIONS, POST, PUT, GET, DELETE)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap the Route with this method to enable adding of CORS headers
|
// Wrap the Route with this method to enable adding of CORS headers
|
||||||
|
@ -51,7 +51,9 @@ object ZipDataDir {
|
|||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length}. Expected: 1"))
|
s"Bad number of arguments: ${other.length}. Expected: 1"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package org.bitcoins.server.routes
|
package org.bitcoins.server.routes
|
||||||
|
|
||||||
/** HTTP errors our server knows how to handle.
|
/** HTTP errors our server knows how to handle. These gets picked up by the
|
||||||
* These gets picked up by the exceptions handler
|
* exceptions handler in Main
|
||||||
* in Main
|
|
||||||
*/
|
*/
|
||||||
sealed abstract class HttpError extends Error
|
sealed abstract class HttpError extends Error
|
||||||
|
|
||||||
|
@ -52,7 +52,8 @@ case class Server(
|
|||||||
rpcport: Int,
|
rpcport: Int,
|
||||||
rpcPassword: String,
|
rpcPassword: String,
|
||||||
wsConfigOpt: Option[WsServerConfig],
|
wsConfigOpt: Option[WsServerConfig],
|
||||||
wsSource: Source[WsNotification[_], NotUsed])(implicit system: ActorSystem)
|
wsSource: Source[WsNotification[_], NotUsed]
|
||||||
|
)(implicit system: ActorSystem)
|
||||||
extends HttpLogger {
|
extends HttpLogger {
|
||||||
|
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
@ -61,8 +62,10 @@ case class Server(
|
|||||||
if (rpchost == "localhost" || rpchost == "127.0.0.1") {
|
if (rpchost == "localhost" || rpchost == "127.0.0.1") {
|
||||||
logger.warn(s"RPC password is not set (rpchost=$rpchost)")
|
logger.warn(s"RPC password is not set (rpchost=$rpchost)")
|
||||||
} else {
|
} else {
|
||||||
require(rpcPassword.nonEmpty,
|
require(
|
||||||
s"RPC password must be set (rpchost=$rpchost)")
|
rpcPassword.nonEmpty,
|
||||||
|
s"RPC password must be set (rpchost=$rpchost)"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +84,8 @@ case class Server(
|
|||||||
complete {
|
complete {
|
||||||
Server.httpError(
|
Server.httpError(
|
||||||
"""Resource not found. Hint: all RPC calls are made against root ('/')""",
|
"""Resource not found. Hint: all RPC calls are made against root ('/')""",
|
||||||
StatusCodes.BadRequest)
|
StatusCodes.BadRequest
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.result()
|
.result()
|
||||||
@ -89,8 +93,11 @@ case class Server(
|
|||||||
val exceptionHandler = ExceptionHandler {
|
val exceptionHandler = ExceptionHandler {
|
||||||
case HttpError.MethodNotFound(method) =>
|
case HttpError.MethodNotFound(method) =>
|
||||||
complete(
|
complete(
|
||||||
Server.httpError(s"'$method' is not a valid method",
|
Server.httpError(
|
||||||
StatusCodes.BadRequest))
|
s"'$method' is not a valid method",
|
||||||
|
StatusCodes.BadRequest
|
||||||
|
)
|
||||||
|
)
|
||||||
case err: Throwable =>
|
case err: Throwable =>
|
||||||
logger.error(s"Unhandled error in server:", err)
|
logger.error(s"Unhandled error in server:", err)
|
||||||
complete(Server.httpError(err.getMessage))
|
complete(Server.httpError(err.getMessage))
|
||||||
@ -173,7 +180,8 @@ case class Server(
|
|||||||
}
|
}
|
||||||
|
|
||||||
DebuggingDirectives.logRequestResult(
|
DebuggingDirectives.logRequestResult(
|
||||||
("http-rpc-server", Logging.DebugLevel)) {
|
("http-rpc-server", Logging.DebugLevel)
|
||||||
|
) {
|
||||||
authenticatedRoute
|
authenticatedRoute
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -250,7 +258,8 @@ object Server extends BitcoinSLogger {
|
|||||||
// TODO id parameter
|
// TODO id parameter
|
||||||
case class Response(
|
case class Response(
|
||||||
result: Option[ujson.Value] = None,
|
result: Option[ujson.Value] = None,
|
||||||
error: Option[String] = None) {
|
error: Option[String] = None
|
||||||
|
) {
|
||||||
|
|
||||||
def toJsonMap: Map[String, ujson.Value] = {
|
def toJsonMap: Map[String, ujson.Value] = {
|
||||||
Map(
|
Map(
|
||||||
@ -267,8 +276,9 @@ object Server extends BitcoinSLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a HTTP response with the given body as a JSON response */
|
/** Creates a HTTP response with the given body as a JSON response */
|
||||||
def httpSuccess[T](body: T)(implicit
|
def httpSuccess[T](
|
||||||
writer: up.Writer[T]): HttpEntity.Strict = {
|
body: T
|
||||||
|
)(implicit writer: up.Writer[T]): HttpEntity.Strict = {
|
||||||
val response = Response(result = Some(up.writeJs(body)))
|
val response = Response(result = Some(up.writeJs(body)))
|
||||||
HttpEntity(
|
HttpEntity(
|
||||||
ContentTypes.`application/json`,
|
ContentTypes.`application/json`,
|
||||||
@ -276,8 +286,9 @@ object Server extends BitcoinSLogger {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def httpSuccessOption[T](bodyOpt: Option[T])(implicit
|
def httpSuccessOption[T](
|
||||||
writer: up.Writer[T]): HttpEntity.Strict = {
|
bodyOpt: Option[T]
|
||||||
|
)(implicit writer: up.Writer[T]): HttpEntity.Strict = {
|
||||||
val response = Response(result = bodyOpt.map(body => up.writeJs(body)))
|
val response = Response(result = bodyOpt.map(body => up.writeJs(body)))
|
||||||
HttpEntity(
|
HttpEntity(
|
||||||
ContentTypes.`application/json`,
|
ContentTypes.`application/json`,
|
||||||
|
@ -2,13 +2,17 @@ package org.bitcoins.server.util
|
|||||||
|
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
|
|
||||||
/** A trait used to indicated when different parts of [[BitcoinSAppConfig]] are started */
|
/** A trait used to indicated when different parts of [[BitcoinSAppConfig]] are
|
||||||
|
* started
|
||||||
|
*/
|
||||||
sealed trait AppConfigMarker
|
sealed trait AppConfigMarker
|
||||||
|
|
||||||
/** This class represents when BitcoinSAppConfig modules are started
|
/** This class represents when BitcoinSAppConfig modules are started
|
||||||
* @param torStartedF this future is completed when all tor dependent modules are fully started
|
* @param torStartedF
|
||||||
* the reason this is needed is because tor startup time is so variable
|
* this future is completed when all tor dependent modules are fully started
|
||||||
* @see https://github.com/bitcoin-s/bitcoin-s/issues/4210
|
* the reason this is needed is because tor startup time is so variable
|
||||||
|
* @see
|
||||||
|
* https://github.com/bitcoin-s/bitcoin-s/issues/4210
|
||||||
*/
|
*/
|
||||||
case class StartedBitcoinSAppConfig(torStartedF: Future[Unit])
|
case class StartedBitcoinSAppConfig(torStartedF: Future[Unit])
|
||||||
extends AppConfigMarker
|
extends AppConfigMarker
|
||||||
|
@ -10,7 +10,9 @@ trait BitcoinSApp {
|
|||||||
|
|
||||||
def commandLineArgs: Array[String]
|
def commandLineArgs: Array[String]
|
||||||
|
|
||||||
/** Useful for projects like the oracle server to specify a custom directory inside of ~./bitcoin-s */
|
/** Useful for projects like the oracle server to specify a custom directory
|
||||||
|
* inside of ~./bitcoin-s
|
||||||
|
*/
|
||||||
def customFinalDirOpt: Option[String]
|
def customFinalDirOpt: Option[String]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,8 +8,8 @@ import scala.concurrent.{ExecutionContext, Future}
|
|||||||
|
|
||||||
case class ServerBindings(
|
case class ServerBindings(
|
||||||
httpServer: Http.ServerBinding,
|
httpServer: Http.ServerBinding,
|
||||||
webSocketServerOpt: Option[Http.ServerBinding])
|
webSocketServerOpt: Option[Http.ServerBinding]
|
||||||
extends BitcoinSLogger {
|
) extends BitcoinSLogger {
|
||||||
|
|
||||||
private val terminateTimeout = 5.seconds
|
private val terminateTimeout = 5.seconds
|
||||||
|
|
||||||
|
@ -27,8 +27,10 @@ class BitcoinSServerMainBitcoindTest
|
|||||||
config: BitcoinSAppConfig =>
|
config: BitcoinSAppConfig =>
|
||||||
val server = new BitcoinSServerMain(ServerArgParser.empty)(system, config)
|
val server = new BitcoinSServerMain(ServerArgParser.empty)(system, config)
|
||||||
|
|
||||||
val cliConfig = Config(rpcPortOpt = Some(config.rpcPort),
|
val cliConfig = Config(
|
||||||
rpcPassword = config.rpcPassword)
|
rpcPortOpt = Some(config.rpcPort),
|
||||||
|
rpcPassword = config.rpcPassword
|
||||||
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
_ <- server.start()
|
_ <- server.start()
|
||||||
@ -38,7 +40,7 @@ class BitcoinSServerMainBitcoindTest
|
|||||||
addr = exec(GetNewAddress(labelOpt = None), cliConfig)
|
addr = exec(GetNewAddress(labelOpt = None), cliConfig)
|
||||||
blockHash = ConsoleCli.exec(CliCommand.GetBestBlockHash, cliConfig)
|
blockHash = ConsoleCli.exec(CliCommand.GetBestBlockHash, cliConfig)
|
||||||
_ <- AsyncUtil.nonBlockingSleep(1.second)
|
_ <- AsyncUtil.nonBlockingSleep(1.second)
|
||||||
_ <- server.stop() //stop to free all resources
|
_ <- server.stop() // stop to free all resources
|
||||||
} yield {
|
} yield {
|
||||||
assert(info.isSuccess)
|
assert(info.isSuccess)
|
||||||
assert(balance.isSuccess)
|
assert(balance.isSuccess)
|
||||||
@ -54,8 +56,10 @@ class BitcoinSServerMainBitcoindTest
|
|||||||
|
|
||||||
val server = new BitcoinSServerMain(ServerArgParser.empty)(system, config)
|
val server = new BitcoinSServerMain(ServerArgParser.empty)(system, config)
|
||||||
|
|
||||||
val cliConfig = Config(rpcPortOpt = Some(config.rpcPort),
|
val cliConfig = Config(
|
||||||
rpcPassword = config.rpcPassword)
|
rpcPortOpt = Some(config.rpcPort),
|
||||||
|
rpcPassword = config.rpcPassword
|
||||||
|
)
|
||||||
|
|
||||||
val mnemonic =
|
val mnemonic =
|
||||||
MnemonicCode.fromEntropy(ECPrivateKey.freshPrivateKey.bytes.toBitVector)
|
MnemonicCode.fromEntropy(ECPrivateKey.freshPrivateKey.bytes.toBitVector)
|
||||||
@ -136,7 +140,8 @@ class BitcoinSServerMainBitcoindTest
|
|||||||
assert(infoT.isFailure)
|
assert(infoT.isFailure)
|
||||||
assert(
|
assert(
|
||||||
infoT.failed.get.getMessage
|
infoT.failed.get.getMessage
|
||||||
.contains("The supplied authentication is invalid"))
|
.contains("The supplied authentication is invalid")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
failF
|
failF
|
||||||
|
@ -21,8 +21,10 @@ class BitcoinSServerMainBitcoindTorTest
|
|||||||
config: BitcoinSAppConfig =>
|
config: BitcoinSAppConfig =>
|
||||||
val server = new BitcoinSServerMain(ServerArgParser.empty)(system, config)
|
val server = new BitcoinSServerMain(ServerArgParser.empty)(system, config)
|
||||||
|
|
||||||
val cliConfig = Config(rpcPortOpt = Some(config.rpcPort),
|
val cliConfig = Config(
|
||||||
rpcPassword = config.rpcPassword)
|
rpcPortOpt = Some(config.rpcPort),
|
||||||
|
rpcPassword = config.rpcPassword
|
||||||
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
_ <- torF
|
_ <- torF
|
||||||
@ -33,7 +35,7 @@ class BitcoinSServerMainBitcoindTorTest
|
|||||||
addr = exec(GetNewAddress(labelOpt = None), cliConfig)
|
addr = exec(GetNewAddress(labelOpt = None), cliConfig)
|
||||||
blockHash = ConsoleCli.exec(CliCommand.GetBestBlockHash, cliConfig)
|
blockHash = ConsoleCli.exec(CliCommand.GetBestBlockHash, cliConfig)
|
||||||
_ <- AsyncUtil.nonBlockingSleep(1.second)
|
_ <- AsyncUtil.nonBlockingSleep(1.second)
|
||||||
_ <- server.stop() //stop to free all resources
|
_ <- server.stop() // stop to free all resources
|
||||||
} yield {
|
} yield {
|
||||||
assert(info.isSuccess)
|
assert(info.isSuccess)
|
||||||
assert(balance.isSuccess)
|
assert(balance.isSuccess)
|
||||||
|
@ -30,7 +30,8 @@ class BitcoindRpcAppConfigTest extends BitcoinSAsyncTest {
|
|||||||
assert(withOther.rpcPort == 5555)
|
assert(withOther.rpcPort == 5555)
|
||||||
|
|
||||||
val mainnetConf = ConfigFactory.parseString(
|
val mainnetConf = ConfigFactory.parseString(
|
||||||
s"bitcoin-s.bitcoind-rpc.rpcport = ${MainNet.rpcPort}")
|
s"bitcoin-s.bitcoind-rpc.rpcport = ${MainNet.rpcPort}"
|
||||||
|
)
|
||||||
val mainnet = withOther.withOverrides(mainnetConf)
|
val mainnet = withOther.withOverrides(mainnetConf)
|
||||||
assert(mainnet.rpcPort == MainNet.rpcPort)
|
assert(mainnet.rpcPort == MainNet.rpcPort)
|
||||||
}
|
}
|
||||||
|
@ -51,8 +51,8 @@ class CallBackUtilTest extends BitcoinSWalletTest {
|
|||||||
_ <- callbacks
|
_ <- callbacks
|
||||||
.executeOnTxReceivedCallbacks(tx2)
|
.executeOnTxReceivedCallbacks(tx2)
|
||||||
.recoverWith { case _: StreamDetachedException =>
|
.recoverWith { case _: StreamDetachedException =>
|
||||||
//expect the stream to be detatched because we stopped
|
// expect the stream to be detatched because we stopped
|
||||||
//the stream with callbacks.stop()
|
// the stream with callbacks.stop()
|
||||||
Future.unit
|
Future.unit
|
||||||
}
|
}
|
||||||
balance3 <- wallet.getBalance()
|
balance3 <- wallet.getBalance()
|
||||||
@ -92,8 +92,8 @@ class CallBackUtilTest extends BitcoinSWalletTest {
|
|||||||
_ <- callbacks
|
_ <- callbacks
|
||||||
.executeOnTxReceivedCallbacks(tx2)
|
.executeOnTxReceivedCallbacks(tx2)
|
||||||
.recoverWith { case _: StreamDetachedException =>
|
.recoverWith { case _: StreamDetachedException =>
|
||||||
//expect the stream to be detatched because we stopped
|
// expect the stream to be detatched because we stopped
|
||||||
//the stream with callbacks.stop()
|
// the stream with callbacks.stop()
|
||||||
Future.unit
|
Future.unit
|
||||||
}
|
}
|
||||||
balance3 <- wallet.getBalance()
|
balance3 <- wallet.getBalance()
|
||||||
|
@ -54,7 +54,8 @@ class CommonRoutesSpec
|
|||||||
|
|
||||||
val route =
|
val route =
|
||||||
commonRoutes.handleCommand(
|
commonRoutes.handleCommand(
|
||||||
ServerCommand("zipdatadir", ujson.Arr(target.toString)))
|
ServerCommand("zipdatadir", ujson.Arr(target.toString))
|
||||||
|
)
|
||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == ContentTypes.`application/json`)
|
assert(contentType == ContentTypes.`application/json`)
|
||||||
|
@ -32,20 +32,22 @@ class DLCRoutesSpec
|
|||||||
|
|
||||||
val dlcRoutes = DLCRoutes(mockNodeApi)
|
val dlcRoutes = DLCRoutes(mockNodeApi)
|
||||||
|
|
||||||
//https://test.oracle.suredbits.com/announcement/8863cd80e1d37f668e27b84cbfed48541d671b4fed1462b86d547e7f13b5a9e4
|
// https://test.oracle.suredbits.com/announcement/8863cd80e1d37f668e27b84cbfed48541d671b4fed1462b86d547e7f13b5a9e4
|
||||||
val announcement = OracleAnnouncementTLV.fromHex(
|
val announcement = OracleAnnouncementTLV.fromHex(
|
||||||
"fdd824c3988fabec9820690f366271c9ceac00fbec1412075f9b319bb0db1f86460519dd9c61478949f2c00c35aeb8e53a1507616072cb802891e2c189a9fa65a0493de5d3b04a6d7b90c9c43c09ebe5250d583e1c3fc423219b26f6a02ec394a130000afdd8225f0001ae3e30df5a203ad10ee89a909df0c8ccea4836e94e0a5d34c3cdab758fcaee1460189600fdd8062400030e52657075626c6963616e5f77696e0c44656d6f637261745f77696e056f7468657210323032302d75732d656c656374696f6e")
|
"fdd824c3988fabec9820690f366271c9ceac00fbec1412075f9b319bb0db1f86460519dd9c61478949f2c00c35aeb8e53a1507616072cb802891e2c189a9fa65a0493de5d3b04a6d7b90c9c43c09ebe5250d583e1c3fc423219b26f6a02ec394a130000afdd8225f0001ae3e30df5a203ad10ee89a909df0c8ccea4836e94e0a5d34c3cdab758fcaee1460189600fdd8062400030e52657075626c6963616e5f77696e0c44656d6f637261745f77696e056f7468657210323032302d75732d656c656374696f6e"
|
||||||
|
)
|
||||||
|
|
||||||
//https://test.oracle.suredbits.com/announcement/362ae482860fc93bac5cbcca3f1f0e49b3c94eac92224a008bd81ef81292f43a
|
// https://test.oracle.suredbits.com/announcement/362ae482860fc93bac5cbcca3f1f0e49b3c94eac92224a008bd81ef81292f43a
|
||||||
val numericAnnouncement = OracleAnnouncementTLV.fromHex(
|
val numericAnnouncement = OracleAnnouncementTLV.fromHex(
|
||||||
"fdd824fd02b9659e890eef1b223ba45c9993f88c7997859302fd5510ac23f4cac0d4ee8232a77ecbdf50c07f093794370e6a506a836f6b0fb54b45f1fb662e1307166d2e57030574f77305826939fa9124d19bfa8a8b2f00f000586b8c58c79ee8b77969a949fdd822fd025300114762c188048a953803f0edeeeb68c69e6cdc1d371ba8d517003accfe05afc4d6588c3ea326512bc66c26a841adffa68330b8c723da442792e731fb19fda94274a7766bb48e520f118c100bbe62dc3806a8d05a63d92e23683a04b0b8c24148cd166585a6b33b995b3d6c083523a8435b156c05100d88f449f4754310d5574d5e88aad09af1b8ba942cfd305e728044ec6360d847254453ec05b1b518a36660e2238360e02f3a004663a7f3a3534973d8b66a2646c1386779aa820672b6361b88a8696395c0add87840b460dfd8a8c0d520017efc6bf58267d4c9d2a225c5d0e5719068a7dda5d630d7432239b6c9d921d5f3842b584503460ca52612ac2e64337d299513690372e8f4770eb8a28080e8d7c29920ca32af470d65d6f916ee81e3ac15ce02684ba6d2522a9ffea1de7e202b4b699ef7ec4f089dda07f3de5b7d1f853b2c56471999be4efca82674a651c80f047ba3a2b9e6f9999f0cd4062c533d1ae29cab2a5e33cbe98728b7b4271c67f7c5cd6e12e39128b9971e08496cbd84cfa99c77c88867d33e73acef37022ba4422a5221776991d45416db71fb54bc6c104f6a8e50e8905161709215104a7e7b97e866f32cf43233ffd615cab66699832ec607cf59c85a7f56fa957aa5f5d7ec9f46d84d5d4b777122d41ad76c6f4968aeedca243f2030d4f502e58f4181130e9afb75309ac21637bcfd0717528bfb82ffe1b6c9fadee6ba70357210990539184bcc913a0ec65837a736733a2fb6172d601b3900fdd80a11000200074254432f55534400000000001117626974636f696e2d732d70726963652d6578616d706c65"
|
"fdd824fd02b9659e890eef1b223ba45c9993f88c7997859302fd5510ac23f4cac0d4ee8232a77ecbdf50c07f093794370e6a506a836f6b0fb54b45f1fb662e1307166d2e57030574f77305826939fa9124d19bfa8a8b2f00f000586b8c58c79ee8b77969a949fdd822fd025300114762c188048a953803f0edeeeb68c69e6cdc1d371ba8d517003accfe05afc4d6588c3ea326512bc66c26a841adffa68330b8c723da442792e731fb19fda94274a7766bb48e520f118c100bbe62dc3806a8d05a63d92e23683a04b0b8c24148cd166585a6b33b995b3d6c083523a8435b156c05100d88f449f4754310d5574d5e88aad09af1b8ba942cfd305e728044ec6360d847254453ec05b1b518a36660e2238360e02f3a004663a7f3a3534973d8b66a2646c1386779aa820672b6361b88a8696395c0add87840b460dfd8a8c0d520017efc6bf58267d4c9d2a225c5d0e5719068a7dda5d630d7432239b6c9d921d5f3842b584503460ca52612ac2e64337d299513690372e8f4770eb8a28080e8d7c29920ca32af470d65d6f916ee81e3ac15ce02684ba6d2522a9ffea1de7e202b4b699ef7ec4f089dda07f3de5b7d1f853b2c56471999be4efca82674a651c80f047ba3a2b9e6f9999f0cd4062c533d1ae29cab2a5e33cbe98728b7b4271c67f7c5cd6e12e39128b9971e08496cbd84cfa99c77c88867d33e73acef37022ba4422a5221776991d45416db71fb54bc6c104f6a8e50e8905161709215104a7e7b97e866f32cf43233ffd615cab66699832ec607cf59c85a7f56fa957aa5f5d7ec9f46d84d5d4b777122d41ad76c6f4968aeedca243f2030d4f502e58f4181130e9afb75309ac21637bcfd0717528bfb82ffe1b6c9fadee6ba70357210990539184bcc913a0ec65837a736733a2fb6172d601b3900fdd80a11000200074254432f55534400000000001117626974636f696e2d732d70726963652d6578616d706c65"
|
||||||
)
|
)
|
||||||
|
|
||||||
//https://test.oracle.suredbits.com/contract/enum/5fbc1d037bacd9ece32ff4b591143bce7fa1c22e0aec2fa8437cc336feb95138
|
// https://test.oracle.suredbits.com/contract/enum/5fbc1d037bacd9ece32ff4b591143bce7fa1c22e0aec2fa8437cc336feb95138
|
||||||
val expectedContractInfo = ContractInfo.fromHex(
|
val expectedContractInfo = ContractInfo.fromHex(
|
||||||
"fdd82efd01120000000005f5e100fda7103b030e52657075626c6963616e5f77696e00000000000000000c44656d6f637261745f77696e0000000005f5e100056f746865720000000003938700fda712c7fdd824c3988fabec9820690f366271c9ceac00fbec1412075f9b319bb0db1f86460519dd9c61478949f2c00c35aeb8e53a1507616072cb802891e2c189a9fa65a0493de5d3b04a6d7b90c9c43c09ebe5250d583e1c3fc423219b26f6a02ec394a130000afdd8225f0001ae3e30df5a203ad10ee89a909df0c8ccea4836e94e0a5d34c3cdab758fcaee1460189600fdd8062400030e52657075626c6963616e5f77696e0c44656d6f637261745f77696e056f7468657210323032302d75732d656c656374696f6e")
|
"fdd82efd01120000000005f5e100fda7103b030e52657075626c6963616e5f77696e00000000000000000c44656d6f637261745f77696e0000000005f5e100056f746865720000000003938700fda712c7fdd824c3988fabec9820690f366271c9ceac00fbec1412075f9b319bb0db1f86460519dd9c61478949f2c00c35aeb8e53a1507616072cb802891e2c189a9fa65a0493de5d3b04a6d7b90c9c43c09ebe5250d583e1c3fc423219b26f6a02ec394a130000afdd8225f0001ae3e30df5a203ad10ee89a909df0c8ccea4836e94e0a5d34c3cdab758fcaee1460189600fdd8062400030e52657075626c6963616e5f77696e0c44656d6f637261745f77696e056f7468657210323032302d75732d656c656374696f6e"
|
||||||
|
)
|
||||||
|
|
||||||
//https://test.oracle.suredbits.com/contract/numeric/d4d4df2892fb2cfd2e8f030f0e69a568e19668b5d355e7713f69853db09a4c33
|
// https://test.oracle.suredbits.com/contract/numeric/d4d4df2892fb2cfd2e8f030f0e69a568e19668b5d355e7713f69853db09a4c33
|
||||||
val expectedNumericContractInfo = ContractInfo.fromHex(
|
val expectedNumericContractInfo = ContractInfo.fromHex(
|
||||||
"fdd82efd032500000000000186a0fda720540011fda72648000501000000000000000000000001fd9c400000000000000000000001fda604000000000000c350000001fdafc800000000000186a0000001fe0001ffff00000000000186a00000fda724020000fda712fd02bffdd824fd02b9659e890eef1b223ba45c9993f88c7997859302fd5510ac23f4cac0d4ee8232a77ecbdf50c07f093794370e6a506a836f6b0fb54b45f1fb662e1307166d2e57030574f77305826939fa9124d19bfa8a8b2f00f000586b8c58c79ee8b77969a949fdd822fd025300114762c188048a953803f0edeeeb68c69e6cdc1d371ba8d517003accfe05afc4d6588c3ea326512bc66c26a841adffa68330b8c723da442792e731fb19fda94274a7766bb48e520f118c100bbe62dc3806a8d05a63d92e23683a04b0b8c24148cd166585a6b33b995b3d6c083523a8435b156c05100d88f449f4754310d5574d5e88aad09af1b8ba942cfd305e728044ec6360d847254453ec05b1b518a36660e2238360e02f3a004663a7f3a3534973d8b66a2646c1386779aa820672b6361b88a8696395c0add87840b460dfd8a8c0d520017efc6bf58267d4c9d2a225c5d0e5719068a7dda5d630d7432239b6c9d921d5f3842b584503460ca52612ac2e64337d299513690372e8f4770eb8a28080e8d7c29920ca32af470d65d6f916ee81e3ac15ce02684ba6d2522a9ffea1de7e202b4b699ef7ec4f089dda07f3de5b7d1f853b2c56471999be4efca82674a651c80f047ba3a2b9e6f9999f0cd4062c533d1ae29cab2a5e33cbe98728b7b4271c67f7c5cd6e12e39128b9971e08496cbd84cfa99c77c88867d33e73acef37022ba4422a5221776991d45416db71fb54bc6c104f6a8e50e8905161709215104a7e7b97e866f32cf43233ffd615cab66699832ec607cf59c85a7f56fa957aa5f5d7ec9f46d84d5d4b777122d41ad76c6f4968aeedca243f2030d4f502e58f4181130e9afb75309ac21637bcfd0717528bfb82ffe1b6c9fadee6ba70357210990539184bcc913a0ec65837a736733a2fb6172d601b3900fdd80a11000200074254432f55534400000000001117626974636f696e2d732d70726963652d6578616d706c65"
|
"fdd82efd032500000000000186a0fda720540011fda72648000501000000000000000000000001fd9c400000000000000000000001fda604000000000000c350000001fdafc800000000000186a0000001fe0001ffff00000000000186a00000fda724020000fda712fd02bffdd824fd02b9659e890eef1b223ba45c9993f88c7997859302fd5510ac23f4cac0d4ee8232a77ecbdf50c07f093794370e6a506a836f6b0fb54b45f1fb662e1307166d2e57030574f77305826939fa9124d19bfa8a8b2f00f000586b8c58c79ee8b77969a949fdd822fd025300114762c188048a953803f0edeeeb68c69e6cdc1d371ba8d517003accfe05afc4d6588c3ea326512bc66c26a841adffa68330b8c723da442792e731fb19fda94274a7766bb48e520f118c100bbe62dc3806a8d05a63d92e23683a04b0b8c24148cd166585a6b33b995b3d6c083523a8435b156c05100d88f449f4754310d5574d5e88aad09af1b8ba942cfd305e728044ec6360d847254453ec05b1b518a36660e2238360e02f3a004663a7f3a3534973d8b66a2646c1386779aa820672b6361b88a8696395c0add87840b460dfd8a8c0d520017efc6bf58267d4c9d2a225c5d0e5719068a7dda5d630d7432239b6c9d921d5f3842b584503460ca52612ac2e64337d299513690372e8f4770eb8a28080e8d7c29920ca32af470d65d6f916ee81e3ac15ce02684ba6d2522a9ffea1de7e202b4b699ef7ec4f089dda07f3de5b7d1f853b2c56471999be4efca82674a651c80f047ba3a2b9e6f9999f0cd4062c533d1ae29cab2a5e33cbe98728b7b4271c67f7c5cd6e12e39128b9971e08496cbd84cfa99c77c88867d33e73acef37022ba4422a5221776991d45416db71fb54bc6c104f6a8e50e8905161709215104a7e7b97e866f32cf43233ffd615cab66699832ec607cf59c85a7f56fa957aa5f5d7ec9f46d84d5d4b777122d41ad76c6f4968aeedca243f2030d4f502e58f4181130e9afb75309ac21637bcfd0717528bfb82ffe1b6c9fadee6ba70357210990539184bcc913a0ec65837a736733a2fb6172d601b3900fdd80a11000200074254432f55534400000000001117626974636f696e2d732d70726963652d6578616d706c65"
|
||||||
)
|
)
|
||||||
@ -84,8 +86,11 @@ class DLCRoutesSpec
|
|||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == ContentTypes.`application/json`)
|
assert(contentType == ContentTypes.`application/json`)
|
||||||
assert(responseAs[
|
assert(
|
||||||
String] == s"""{"result":"${expectedContractInfo.hex}","error":null}""")
|
responseAs[
|
||||||
|
String
|
||||||
|
] == s"""{"result":"${expectedContractInfo.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,8 +152,11 @@ class DLCRoutesSpec
|
|||||||
|
|
||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == ContentTypes.`application/json`)
|
assert(contentType == ContentTypes.`application/json`)
|
||||||
assert(responseAs[
|
assert(
|
||||||
String] == s"""{"result":"${expectedNumericContractInfo.hex}","error":null}""")
|
responseAs[
|
||||||
|
String
|
||||||
|
] == s"""{"result":"${expectedNumericContractInfo.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +230,8 @@ class DLCRoutesSpec
|
|||||||
Post() ~> route ~> check {
|
Post() ~> route ~> check {
|
||||||
assert(contentType == ContentTypes.`application/json`)
|
assert(contentType == ContentTypes.`application/json`)
|
||||||
assert(
|
assert(
|
||||||
responseAs[String] == s"""{"result":{"dlcId":"0000000000000000000000000000000000000000000000000000000000000000","contactId":"i3bfhauurptgypgnolqmj7xxv7pcs5c6udtzthbgojc7eaxx6zbbjyad.onion:2862"},"error":null}""")
|
responseAs[String] == s"""{"result":{"dlcId":"0000000000000000000000000000000000000000000000000000000000000000","contactId":"i3bfhauurptgypgnolqmj7xxv7pcs5c6udtzthbgojc7eaxx6zbbjyad.onion:2862"},"error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,38 +34,41 @@ class DLCWalletBitcoindBackendLoaderTest extends WalletLoaderFixtures {
|
|||||||
it must "track rescan state accurately" in { walletHolderWithLoader =>
|
it must "track rescan state accurately" in { walletHolderWithLoader =>
|
||||||
val loader = walletHolderWithLoader.loaderApi
|
val loader = walletHolderWithLoader.loaderApi
|
||||||
val bitcoind = walletHolderWithLoader.bitcoind
|
val bitcoind = walletHolderWithLoader.bitcoind
|
||||||
//need some blocks to make rescans last longer for the test case
|
// need some blocks to make rescans last longer for the test case
|
||||||
val blocksF = bitcoind.generate(250)
|
val blocksF = bitcoind.generate(250)
|
||||||
|
|
||||||
val loadedWalletF = loader.load(walletNameOpt = None, aesPasswordOpt = None)
|
val loadedWalletF = loader.load(walletNameOpt = None, aesPasswordOpt = None)
|
||||||
|
|
||||||
val walletConfigF = loadedWalletF.map(_._2)
|
val walletConfigF = loadedWalletF.map(_._2)
|
||||||
|
|
||||||
//as a hack, set rescanning to true, so next time we load it starts a rescan
|
// as a hack, set rescanning to true, so next time we load it starts a rescan
|
||||||
val setRescanF = for {
|
val setRescanF = for {
|
||||||
_ <- blocksF
|
_ <- blocksF
|
||||||
walletConfig <- walletConfigF
|
walletConfig <- walletConfigF
|
||||||
descriptorDAO = WalletStateDescriptorDAO()(system.dispatcher,
|
descriptorDAO = WalletStateDescriptorDAO()(
|
||||||
walletConfig)
|
system.dispatcher,
|
||||||
|
walletConfig
|
||||||
|
)
|
||||||
set <- descriptorDAO.compareAndSetRescanning(false, true)
|
set <- descriptorDAO.compareAndSetRescanning(false, true)
|
||||||
} yield assert(set)
|
} yield assert(set)
|
||||||
|
|
||||||
//now that we have set rescanning, we should see a rescan next time we load wallet
|
// now that we have set rescanning, we should see a rescan next time we load wallet
|
||||||
for {
|
for {
|
||||||
_ <- setRescanF
|
_ <- setRescanF
|
||||||
(loadWallet2, _, _) <- loader.load(
|
(loadWallet2, _, _) <- loader.load(
|
||||||
walletNameOpt = None,
|
walletNameOpt = None,
|
||||||
aesPasswordOpt = None
|
aesPasswordOpt = None
|
||||||
) //load wallet again
|
) // load wallet again
|
||||||
isRescanning <- loadWallet2.isRescanning()
|
isRescanning <- loadWallet2.isRescanning()
|
||||||
_ = assert(isRescanning)
|
_ = assert(isRescanning)
|
||||||
_ = assert(loader.isRescanStateDefined)
|
_ = assert(loader.isRescanStateDefined)
|
||||||
//wait until rescanning is done
|
// wait until rescanning is done
|
||||||
_ <- AsyncUtil.retryUntilSatisfiedF(
|
_ <- AsyncUtil.retryUntilSatisfiedF(
|
||||||
{ () =>
|
{ () =>
|
||||||
loadWallet2.isRescanning().map(isRescanning => isRescanning == false)
|
loadWallet2.isRescanning().map(isRescanning => isRescanning == false)
|
||||||
},
|
},
|
||||||
1.second)
|
1.second
|
||||||
|
)
|
||||||
} yield {
|
} yield {
|
||||||
assert(loader.isRescanStateEmpty)
|
assert(loader.isRescanStateEmpty)
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -18,8 +18,8 @@ class ServerRunTest extends BitcoinSAsyncTest {
|
|||||||
// Note: on this test passing it will output a stack trace
|
// Note: on this test passing it will output a stack trace
|
||||||
// because runMain calls err.printStackTrace() on failure
|
// because runMain calls err.printStackTrace() on failure
|
||||||
it must "throw errors" in {
|
it must "throw errors" in {
|
||||||
//custom configuration to make peers empty
|
// custom configuration to make peers empty
|
||||||
//this should cause an exception in startBitcoinSBackend()
|
// this should cause an exception in startBitcoinSBackend()
|
||||||
val noPeersConfig =
|
val noPeersConfig =
|
||||||
ConfigFactory.parseString(s"""bitcoin-s.node.peers=[]""")
|
ConfigFactory.parseString(s"""bitcoin-s.node.peers=[]""")
|
||||||
implicit val config =
|
implicit val config =
|
||||||
@ -27,10 +27,12 @@ class ServerRunTest extends BitcoinSAsyncTest {
|
|||||||
val datadir = config.chainConf.datadir
|
val datadir = config.chainConf.datadir
|
||||||
|
|
||||||
val invalidPort = -1
|
val invalidPort = -1
|
||||||
val args = Vector("--datadir",
|
val args = Vector(
|
||||||
datadir.toAbsolutePath.toString,
|
"--datadir",
|
||||||
"--rpcport",
|
datadir.toAbsolutePath.toString,
|
||||||
invalidPort.toString)
|
"--rpcport",
|
||||||
|
invalidPort.toString
|
||||||
|
)
|
||||||
|
|
||||||
val serverArgParser = ServerArgParser(args)
|
val serverArgParser = ServerArgParser(args)
|
||||||
val main = new BitcoinSServerMain(serverArgParser)
|
val main = new BitcoinSServerMain(serverArgParser)
|
||||||
|
@ -40,10 +40,12 @@ class WalletRoutesSpec
|
|||||||
val feeRateApi = ConstantFeeRateProvider(SatoshisPerVirtualByte.one)
|
val feeRateApi = ConstantFeeRateProvider(SatoshisPerVirtualByte.one)
|
||||||
|
|
||||||
val walletLoader: DLCWalletNeutrinoBackendLoader =
|
val walletLoader: DLCWalletNeutrinoBackendLoader =
|
||||||
DLCWalletNeutrinoBackendLoader(walletHolder,
|
DLCWalletNeutrinoBackendLoader(
|
||||||
mockChainApi,
|
walletHolder,
|
||||||
mockNode,
|
mockChainApi,
|
||||||
feeRateApi)
|
mockNode,
|
||||||
|
feeRateApi
|
||||||
|
)
|
||||||
|
|
||||||
val walletRoutes: WalletRoutes =
|
val walletRoutes: WalletRoutes =
|
||||||
WalletRoutes(walletLoader)(system, conf.walletConf)
|
WalletRoutes(walletLoader)(system, conf.walletConf)
|
||||||
@ -101,7 +103,8 @@ class WalletRoutesSpec
|
|||||||
)
|
)
|
||||||
|
|
||||||
(mockWalletApi.findDLCByTemporaryContractId: Sha256Digest => Future[
|
(mockWalletApi.findDLCByTemporaryContractId: Sha256Digest => Future[
|
||||||
Option[DLCStatus]])
|
Option[DLCStatus]
|
||||||
|
])
|
||||||
.expects(tempContractId)
|
.expects(tempContractId)
|
||||||
.returning(Future.successful(Some(status)))
|
.returning(Future.successful(Some(status)))
|
||||||
(mockWalletApi.getDLCOffer: Sha256Digest => Future[Option[DLCOffer]])
|
(mockWalletApi.getDLCOffer: Sha256Digest => Future[Option[DLCOffer]])
|
||||||
@ -110,7 +113,8 @@ class WalletRoutesSpec
|
|||||||
|
|
||||||
val route =
|
val route =
|
||||||
walletRoutes.handleCommand(
|
walletRoutes.handleCommand(
|
||||||
ServerCommand("getdlcoffer", ujson.Arr(tempContractId.hex)))
|
ServerCommand("getdlcoffer", ujson.Arr(tempContractId.hex))
|
||||||
|
)
|
||||||
|
|
||||||
Get() ~> route ~> check {
|
Get() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
@ -127,23 +131,28 @@ class WalletRoutesSpec
|
|||||||
LnMessage(TLVGen.dlcAcceptTLV(offer.toTLV).sampleSome)
|
LnMessage(TLVGen.dlcAcceptTLV(offer.toTLV).sampleSome)
|
||||||
val acceptTLV = DLCAccept.fromTLV(dummyAcceptLnMsg.tlv, offer)
|
val acceptTLV = DLCAccept.fromTLV(dummyAcceptLnMsg.tlv, offer)
|
||||||
(mockWalletApi
|
(mockWalletApi
|
||||||
.acceptDLCOffer(_: DLCOfferTLV,
|
.acceptDLCOffer(
|
||||||
_: Option[InetSocketAddress],
|
_: DLCOfferTLV,
|
||||||
_: Option[BitcoinAddress],
|
_: Option[InetSocketAddress],
|
||||||
_: Option[BitcoinAddress]))
|
_: Option[BitcoinAddress],
|
||||||
|
_: Option[BitcoinAddress]
|
||||||
|
))
|
||||||
.expects(expectedTlv, None, None, None)
|
.expects(expectedTlv, None, None, None)
|
||||||
.returning(Future.successful(acceptTLV))
|
.returning(Future.successful(acceptTLV))
|
||||||
|
|
||||||
val cmd = ServerCommand(
|
val cmd = ServerCommand(
|
||||||
"acceptdlcoffer",
|
"acceptdlcoffer",
|
||||||
ujson.Arr(ujson.Str(tlv), ujson.Null, ujson.Null, ujson.Null))
|
ujson.Arr(ujson.Str(tlv), ujson.Null, ujson.Null, ujson.Null)
|
||||||
|
)
|
||||||
val route = walletRoutes.handleCommand(cmd)
|
val route = walletRoutes.handleCommand(cmd)
|
||||||
|
|
||||||
Get() ~> route ~> check {
|
Get() ~> route ~> check {
|
||||||
assert(contentType == `application/json`)
|
assert(contentType == `application/json`)
|
||||||
assert(
|
assert(
|
||||||
responseAs[
|
responseAs[
|
||||||
String] == s"""{"result":"${dummyAcceptLnMsg.hex}","error":null}""")
|
String
|
||||||
|
] == s"""{"result":"${dummyAcceptLnMsg.hex}","error":null}"""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,19 +56,26 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
val sink: Sink[Message, Future[Seq[WsNotification[_]]]] = Flow[Message]
|
val sink: Sink[Message, Future[Seq[WsNotification[_]]]] = Flow[Message]
|
||||||
.map {
|
.map {
|
||||||
case message: TextMessage.Strict =>
|
case message: TextMessage.Strict =>
|
||||||
//we should be able to parse the address message
|
// we should be able to parse the address message
|
||||||
val text = message.text
|
val text = message.text
|
||||||
val dlcNodeNotificationOpt: Option[DLCNodeNotification[_]] = Try(
|
val dlcNodeNotificationOpt: Option[DLCNodeNotification[_]] = Try(
|
||||||
upickle.default.read[DLCNodeNotification[_]](text)(
|
upickle.default.read[DLCNodeNotification[_]](text)(
|
||||||
WsPicklers.dlcNodeNotificationPickler)).toOption
|
WsPicklers.dlcNodeNotificationPickler
|
||||||
|
)
|
||||||
|
).toOption
|
||||||
val walletNotificationOpt: Option[WalletNotification[_]] = Try(
|
val walletNotificationOpt: Option[WalletNotification[_]] = Try(
|
||||||
upickle.default.read[WalletNotification[_]](text)(
|
upickle.default.read[WalletNotification[_]](text)(
|
||||||
WsPicklers.walletNotificationPickler)).toOption
|
WsPicklers.walletNotificationPickler
|
||||||
|
)
|
||||||
|
).toOption
|
||||||
val chainNotificationOpt: Option[ChainNotification[_]] = Try(
|
val chainNotificationOpt: Option[ChainNotification[_]] = Try(
|
||||||
upickle.default.read[ChainNotification[_]](text)(
|
upickle.default.read[ChainNotification[_]](text)(
|
||||||
WsPicklers.chainNotificationPickler)).toOption
|
WsPicklers.chainNotificationPickler
|
||||||
|
)
|
||||||
|
).toOption
|
||||||
walletNotificationOpt.getOrElse(
|
walletNotificationOpt.getOrElse(
|
||||||
chainNotificationOpt.getOrElse(dlcNodeNotificationOpt.get))
|
chainNotificationOpt.getOrElse(dlcNodeNotificationOpt.get)
|
||||||
|
)
|
||||||
case msg =>
|
case msg =>
|
||||||
fail(s"Unexpected msg type received in the sink, msg=$msg")
|
fail(s"Unexpected msg type received in the sink, msg=$msg")
|
||||||
}
|
}
|
||||||
@ -76,19 +83,27 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
|
|
||||||
def buildReq(
|
def buildReq(
|
||||||
conf: BitcoinSAppConfig,
|
conf: BitcoinSAppConfig,
|
||||||
rpcPassword: Option[String] = None): WebSocketRequest = {
|
rpcPassword: Option[String] = None
|
||||||
|
): WebSocketRequest = {
|
||||||
val headers: Vector[HttpHeader] = Vector(
|
val headers: Vector[HttpHeader] = Vector(
|
||||||
Authorization(
|
Authorization(
|
||||||
BasicHttpCredentials("bitcoins",
|
BasicHttpCredentials(
|
||||||
rpcPassword.getOrElse(conf.rpcPassword))))
|
"bitcoins",
|
||||||
WebSocketRequest(s"ws://localhost:${conf.wsPort}/events",
|
rpcPassword.getOrElse(conf.rpcPassword)
|
||||||
extraHeaders = headers)
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
WebSocketRequest(
|
||||||
|
s"ws://localhost:${conf.wsPort}/events",
|
||||||
|
extraHeaders = headers
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val websocketFlow: Flow[
|
val websocketFlow: Flow[
|
||||||
Message,
|
Message,
|
||||||
Message,
|
Message,
|
||||||
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])] = {
|
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])
|
||||||
|
] = {
|
||||||
Flow
|
Flow
|
||||||
.fromSinkAndSourceCoupledMat(sink, Source.maybe[Message])(Keep.both)
|
.fromSinkAndSourceCoupledMat(sink, Source.maybe[Message])(Keep.both)
|
||||||
}
|
}
|
||||||
@ -133,26 +148,32 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
} yield {
|
} yield {
|
||||||
assert(response.response.status == StatusCodes.Unauthorized)
|
assert(response.response.status == StatusCodes.Unauthorized)
|
||||||
|
|
||||||
val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort),
|
val cliConfig = Config(
|
||||||
rpcPassword = "wrong password")
|
rpcPortOpt = Some(server.conf.rpcPort),
|
||||||
|
rpcPassword = "wrong password"
|
||||||
|
)
|
||||||
val cliResponse = exec(GetNewAddress(labelOpt = None), cliConfig)
|
val cliResponse = exec(GetNewAddress(labelOpt = None), cliConfig)
|
||||||
|
|
||||||
assert(cliResponse.isFailure)
|
assert(cliResponse.isFailure)
|
||||||
assert(
|
assert(
|
||||||
cliResponse.failed.get.getMessage == "The supplied authentication is invalid")
|
cliResponse.failed.get.getMessage == "The supplied authentication is invalid"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
it must "receive updates when an address is generated" in {
|
it must "receive updates when an address is generated" in {
|
||||||
serverWithBitcoind =>
|
serverWithBitcoind =>
|
||||||
val ServerWithBitcoind(_, server) = serverWithBitcoind
|
val ServerWithBitcoind(_, server) = serverWithBitcoind
|
||||||
val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort),
|
val cliConfig = Config(
|
||||||
rpcPassword = server.conf.rpcPassword)
|
rpcPortOpt = Some(server.conf.rpcPort),
|
||||||
|
rpcPassword = server.conf.rpcPassword
|
||||||
|
)
|
||||||
|
|
||||||
val req = buildReq(server.conf)
|
val req = buildReq(server.conf)
|
||||||
val notificationsF: (
|
val notificationsF: (
|
||||||
Future[WebSocketUpgradeResponse],
|
Future[WebSocketUpgradeResponse],
|
||||||
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = {
|
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])
|
||||||
|
) = {
|
||||||
Http()
|
Http()
|
||||||
.singleWebSocketRequest(req, websocketFlow)
|
.singleWebSocketRequest(req, websocketFlow)
|
||||||
}
|
}
|
||||||
@ -171,20 +192,24 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
notifications <- walletNotificationsF
|
notifications <- walletNotificationsF
|
||||||
} yield {
|
} yield {
|
||||||
assert(
|
assert(
|
||||||
notifications.exists(_ == NewAddressNotification(expectedAddress)))
|
notifications.exists(_ == NewAddressNotification(expectedAddress))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
it must "receive updates when a transaction is broadcast" in {
|
it must "receive updates when a transaction is broadcast" in {
|
||||||
serverWithBitcoind =>
|
serverWithBitcoind =>
|
||||||
val ServerWithBitcoind(bitcoind, server) = serverWithBitcoind
|
val ServerWithBitcoind(bitcoind, server) = serverWithBitcoind
|
||||||
val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort),
|
val cliConfig = Config(
|
||||||
rpcPassword = server.conf.rpcPassword)
|
rpcPortOpt = Some(server.conf.rpcPort),
|
||||||
|
rpcPassword = server.conf.rpcPassword
|
||||||
|
)
|
||||||
|
|
||||||
val req = buildReq(server.conf)
|
val req = buildReq(server.conf)
|
||||||
val tuple: (
|
val tuple: (
|
||||||
Future[WebSocketUpgradeResponse],
|
Future[WebSocketUpgradeResponse],
|
||||||
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = {
|
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])
|
||||||
|
) = {
|
||||||
Http()
|
Http()
|
||||||
.singleWebSocketRequest(req, websocketFlow)
|
.singleWebSocketRequest(req, websocketFlow)
|
||||||
}
|
}
|
||||||
@ -196,11 +221,12 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
address <- addressF
|
address <- addressF
|
||||||
cmd = SendToAddress(destination = address,
|
cmd = SendToAddress(
|
||||||
amount = Bitcoins.one,
|
destination = address,
|
||||||
satoshisPerVirtualByte =
|
amount = Bitcoins.one,
|
||||||
Some(SatoshisPerVirtualByte.one),
|
satoshisPerVirtualByte = Some(SatoshisPerVirtualByte.one),
|
||||||
noBroadcast = false)
|
noBroadcast = false
|
||||||
|
)
|
||||||
txIdStr = ConsoleCli.exec(cmd, cliConfig)
|
txIdStr = ConsoleCli.exec(cmd, cliConfig)
|
||||||
expectedTxId = DoubleSha256DigestBE.fromHex(txIdStr.get)
|
expectedTxId = DoubleSha256DigestBE.fromHex(txIdStr.get)
|
||||||
getTxCmd = GetTransaction(expectedTxId)
|
getTxCmd = GetTransaction(expectedTxId)
|
||||||
@ -217,13 +243,16 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
it must "receive updates when a transaction is processed" in {
|
it must "receive updates when a transaction is processed" in {
|
||||||
serverWithBitcoind =>
|
serverWithBitcoind =>
|
||||||
val ServerWithBitcoind(bitcoind, server) = serverWithBitcoind
|
val ServerWithBitcoind(bitcoind, server) = serverWithBitcoind
|
||||||
val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort),
|
val cliConfig = Config(
|
||||||
rpcPassword = server.conf.rpcPassword)
|
rpcPortOpt = Some(server.conf.rpcPort),
|
||||||
|
rpcPassword = server.conf.rpcPassword
|
||||||
|
)
|
||||||
|
|
||||||
val req = buildReq(server.conf)
|
val req = buildReq(server.conf)
|
||||||
val tuple: (
|
val tuple: (
|
||||||
Future[WebSocketUpgradeResponse],
|
Future[WebSocketUpgradeResponse],
|
||||||
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = {
|
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])
|
||||||
|
) = {
|
||||||
Http()
|
Http()
|
||||||
.singleWebSocketRequest(req, websocketFlow)
|
.singleWebSocketRequest(req, websocketFlow)
|
||||||
}
|
}
|
||||||
@ -235,11 +264,12 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
address <- addressF
|
address <- addressF
|
||||||
cmd = SendToAddress(destination = address,
|
cmd = SendToAddress(
|
||||||
amount = Bitcoins.one,
|
destination = address,
|
||||||
satoshisPerVirtualByte =
|
amount = Bitcoins.one,
|
||||||
Some(SatoshisPerVirtualByte.one),
|
satoshisPerVirtualByte = Some(SatoshisPerVirtualByte.one),
|
||||||
noBroadcast = false)
|
noBroadcast = false
|
||||||
|
)
|
||||||
txIdStr = ConsoleCli.exec(cmd, cliConfig)
|
txIdStr = ConsoleCli.exec(cmd, cliConfig)
|
||||||
expectedTxId = DoubleSha256DigestBE.fromHex(txIdStr.get)
|
expectedTxId = DoubleSha256DigestBE.fromHex(txIdStr.get)
|
||||||
getTxCmd = GetTransaction(expectedTxId)
|
getTxCmd = GetTransaction(expectedTxId)
|
||||||
@ -255,13 +285,16 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
|
|
||||||
it must "receive updates when a block is processed" in { serverWithBitcoind =>
|
it must "receive updates when a block is processed" in { serverWithBitcoind =>
|
||||||
val ServerWithBitcoind(bitcoind, server) = serverWithBitcoind
|
val ServerWithBitcoind(bitcoind, server) = serverWithBitcoind
|
||||||
val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort),
|
val cliConfig = Config(
|
||||||
rpcPassword = server.conf.rpcPassword)
|
rpcPortOpt = Some(server.conf.rpcPort),
|
||||||
|
rpcPassword = server.conf.rpcPassword
|
||||||
|
)
|
||||||
|
|
||||||
val req = buildReq(server.conf)
|
val req = buildReq(server.conf)
|
||||||
val tuple: (
|
val tuple: (
|
||||||
Future[WebSocketUpgradeResponse],
|
Future[WebSocketUpgradeResponse],
|
||||||
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = {
|
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])
|
||||||
|
) = {
|
||||||
Http()
|
Http()
|
||||||
.singleWebSocketRequest(req, websocketFlow)
|
.singleWebSocketRequest(req, websocketFlow)
|
||||||
}
|
}
|
||||||
@ -271,20 +304,22 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
|
|
||||||
val addressF = bitcoind.getNewAddress
|
val addressF = bitcoind.getNewAddress
|
||||||
val timeout =
|
val timeout =
|
||||||
15.seconds //any way we can remove this timeout and just check?
|
15.seconds // any way we can remove this timeout and just check?
|
||||||
for {
|
for {
|
||||||
address <- addressF
|
address <- addressF
|
||||||
hashes <- bitcoind.generateToAddress(1, address)
|
hashes <- bitcoind.generateToAddress(1, address)
|
||||||
cmd = GetBlockHeader(hash = hashes.head)
|
cmd = GetBlockHeader(hash = hashes.head)
|
||||||
getBlockHeaderResultStr = ConsoleCli.exec(cmd, cliConfig)
|
getBlockHeaderResultStr = ConsoleCli.exec(cmd, cliConfig)
|
||||||
getBlockHeaderResult = upickle.default.read(getBlockHeaderResultStr.get)(
|
getBlockHeaderResult = upickle.default.read(getBlockHeaderResultStr.get)(
|
||||||
Picklers.getBlockHeaderResultPickler)
|
Picklers.getBlockHeaderResultPickler
|
||||||
|
)
|
||||||
_ <- PekkoUtil.nonBlockingSleep(timeout)
|
_ <- PekkoUtil.nonBlockingSleep(timeout)
|
||||||
_ = promise.success(None)
|
_ = promise.success(None)
|
||||||
notifications <- notificationsF
|
notifications <- notificationsF
|
||||||
} yield {
|
} yield {
|
||||||
val count = notifications.count(
|
val count = notifications.count(
|
||||||
_ == BlockProcessedNotification(getBlockHeaderResult))
|
_ == BlockProcessedNotification(getBlockHeaderResult)
|
||||||
|
)
|
||||||
assert(count == 1, s"count=$count")
|
assert(count == 1, s"count=$count")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,13 +327,16 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
it must "get notifications for reserving and unreserving utxos" in {
|
it must "get notifications for reserving and unreserving utxos" in {
|
||||||
serverWithBitcoind =>
|
serverWithBitcoind =>
|
||||||
val ServerWithBitcoind(_, server) = serverWithBitcoind
|
val ServerWithBitcoind(_, server) = serverWithBitcoind
|
||||||
val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort),
|
val cliConfig = Config(
|
||||||
rpcPassword = server.conf.rpcPassword)
|
rpcPortOpt = Some(server.conf.rpcPort),
|
||||||
|
rpcPassword = server.conf.rpcPassword
|
||||||
|
)
|
||||||
|
|
||||||
val req = buildReq(server.conf)
|
val req = buildReq(server.conf)
|
||||||
val tuple: (
|
val tuple: (
|
||||||
Future[WebSocketUpgradeResponse],
|
Future[WebSocketUpgradeResponse],
|
||||||
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = {
|
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])
|
||||||
|
) = {
|
||||||
Http()
|
Http()
|
||||||
.singleWebSocketRequest(req, websocketFlow)
|
.singleWebSocketRequest(req, websocketFlow)
|
||||||
}
|
}
|
||||||
@ -306,11 +344,11 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
val notificationsF: Future[Seq[WsNotification[_]]] = tuple._2._1
|
val notificationsF: Future[Seq[WsNotification[_]]] = tuple._2._1
|
||||||
val promise = tuple._2._2
|
val promise = tuple._2._2
|
||||||
|
|
||||||
//lock all utxos
|
// lock all utxos
|
||||||
val lockCmd = LockUnspent(unlock = false, Vector.empty)
|
val lockCmd = LockUnspent(unlock = false, Vector.empty)
|
||||||
ConsoleCli.exec(lockCmd, cliConfig)
|
ConsoleCli.exec(lockCmd, cliConfig)
|
||||||
|
|
||||||
//unlock all utxos
|
// unlock all utxos
|
||||||
val unlockCmd = LockUnspent(unlock = true, Vector.empty)
|
val unlockCmd = LockUnspent(unlock = true, Vector.empty)
|
||||||
ConsoleCli.exec(unlockCmd, cliConfig)
|
ConsoleCli.exec(unlockCmd, cliConfig)
|
||||||
|
|
||||||
@ -319,7 +357,7 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
_ = promise.success(None)
|
_ = promise.success(None)
|
||||||
notifications <- notificationsF
|
notifications <- notificationsF
|
||||||
} yield {
|
} yield {
|
||||||
//should have two notifications for locking and then unlocking the utxos
|
// should have two notifications for locking and then unlocking the utxos
|
||||||
assert(notifications.count(_.`type` == WalletWsType.ReservedUtxos) == 2)
|
assert(notifications.count(_.`type` == WalletWsType.ReservedUtxos) == 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -327,13 +365,16 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
it must "receive updates when an offer is added and removed" in {
|
it must "receive updates when an offer is added and removed" in {
|
||||||
serverWithBitcoind =>
|
serverWithBitcoind =>
|
||||||
val ServerWithBitcoind(_, server) = serverWithBitcoind
|
val ServerWithBitcoind(_, server) = serverWithBitcoind
|
||||||
val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort),
|
val cliConfig = Config(
|
||||||
rpcPassword = server.conf.rpcPassword)
|
rpcPortOpt = Some(server.conf.rpcPort),
|
||||||
|
rpcPassword = server.conf.rpcPassword
|
||||||
|
)
|
||||||
|
|
||||||
val req = buildReq(server.conf)
|
val req = buildReq(server.conf)
|
||||||
val notificationsF: (
|
val notificationsF: (
|
||||||
Future[WebSocketUpgradeResponse],
|
Future[WebSocketUpgradeResponse],
|
||||||
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = {
|
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])
|
||||||
|
) = {
|
||||||
Http()
|
Http()
|
||||||
.singleWebSocketRequest(req, websocketFlow)
|
.singleWebSocketRequest(req, websocketFlow)
|
||||||
}
|
}
|
||||||
@ -348,7 +389,8 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
ConsoleCli
|
ConsoleCli
|
||||||
.exec(
|
.exec(
|
||||||
CliCommand.AddDLCOffer(offer = offer, message = "msg", peer = "uri"),
|
CliCommand.AddDLCOffer(offer = offer, message = "msg", peer = "uri"),
|
||||||
cliConfig)
|
cliConfig
|
||||||
|
)
|
||||||
.get
|
.get
|
||||||
|
|
||||||
ConsoleCli
|
ConsoleCli
|
||||||
@ -376,23 +418,28 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
|
|
||||||
it must "receive updates when a rescan is complete" in { serverWithBitcoind =>
|
it must "receive updates when a rescan is complete" in { serverWithBitcoind =>
|
||||||
val ServerWithBitcoind(_, server) = serverWithBitcoind
|
val ServerWithBitcoind(_, server) = serverWithBitcoind
|
||||||
val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort),
|
val cliConfig = Config(
|
||||||
rpcPassword = server.conf.rpcPassword)
|
rpcPortOpt = Some(server.conf.rpcPort),
|
||||||
|
rpcPassword = server.conf.rpcPassword
|
||||||
|
)
|
||||||
|
|
||||||
val req = buildReq(server.conf)
|
val req = buildReq(server.conf)
|
||||||
val tuple: (
|
val tuple: (
|
||||||
Future[WebSocketUpgradeResponse],
|
Future[WebSocketUpgradeResponse],
|
||||||
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = {
|
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])
|
||||||
|
) = {
|
||||||
Http()
|
Http()
|
||||||
.singleWebSocketRequest(req, websocketFlow)
|
.singleWebSocketRequest(req, websocketFlow)
|
||||||
}
|
}
|
||||||
val notificationsF = tuple._2._1
|
val notificationsF = tuple._2._1
|
||||||
val promise = tuple._2._2
|
val promise = tuple._2._2
|
||||||
val cmd = Rescan(batchSize = None,
|
val cmd = Rescan(
|
||||||
startBlock = None,
|
batchSize = None,
|
||||||
endBlock = None,
|
startBlock = None,
|
||||||
force = true,
|
endBlock = None,
|
||||||
ignoreCreationTime = false)
|
force = true,
|
||||||
|
ignoreCreationTime = false
|
||||||
|
)
|
||||||
val _ = ConsoleCli.exec(cmd, cliConfig)
|
val _ = ConsoleCli.exec(cmd, cliConfig)
|
||||||
for {
|
for {
|
||||||
_ <- PekkoUtil.nonBlockingSleep(10.second)
|
_ <- PekkoUtil.nonBlockingSleep(10.second)
|
||||||
@ -410,7 +457,8 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
val req = buildReq(server.conf)
|
val req = buildReq(server.conf)
|
||||||
val tuple: (
|
val tuple: (
|
||||||
Future[WebSocketUpgradeResponse],
|
Future[WebSocketUpgradeResponse],
|
||||||
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = {
|
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])
|
||||||
|
) = {
|
||||||
Http()
|
Http()
|
||||||
.singleWebSocketRequest(req, websocketFlow)
|
.singleWebSocketRequest(req, websocketFlow)
|
||||||
}
|
}
|
||||||
@ -434,7 +482,8 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
val req = buildReq(server.conf)
|
val req = buildReq(server.conf)
|
||||||
val tuple: (
|
val tuple: (
|
||||||
Future[WebSocketUpgradeResponse],
|
Future[WebSocketUpgradeResponse],
|
||||||
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = {
|
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])
|
||||||
|
) = {
|
||||||
Http()
|
Http()
|
||||||
.singleWebSocketRequest(req, websocketFlow)
|
.singleWebSocketRequest(req, websocketFlow)
|
||||||
}
|
}
|
||||||
@ -453,13 +502,16 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
|
|
||||||
it must "receive dlc node updates" in { serverWithBitcoind =>
|
it must "receive dlc node updates" in { serverWithBitcoind =>
|
||||||
val ServerWithBitcoind(_, server) = serverWithBitcoind
|
val ServerWithBitcoind(_, server) = serverWithBitcoind
|
||||||
val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort),
|
val cliConfig = Config(
|
||||||
rpcPassword = server.conf.rpcPassword)
|
rpcPortOpt = Some(server.conf.rpcPort),
|
||||||
|
rpcPassword = server.conf.rpcPassword
|
||||||
|
)
|
||||||
|
|
||||||
val req = buildReq(server.conf)
|
val req = buildReq(server.conf)
|
||||||
val notificationsF: (
|
val notificationsF: (
|
||||||
Future[WebSocketUpgradeResponse],
|
Future[WebSocketUpgradeResponse],
|
||||||
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = {
|
(Future[Seq[WsNotification[_]]], Promise[Option[Message]])
|
||||||
|
) = {
|
||||||
Http()
|
Http()
|
||||||
.singleWebSocketRequest(req, websocketFlow)
|
.singleWebSocketRequest(req, websocketFlow)
|
||||||
}
|
}
|
||||||
@ -474,10 +526,12 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
InetSocketAddress.createUnresolved("127.0.0.1", NetworkUtil.randomPort())
|
InetSocketAddress.createUnresolved("127.0.0.1", NetworkUtil.randomPort())
|
||||||
|
|
||||||
val acceptMsg = {
|
val acceptMsg = {
|
||||||
AcceptDLC(offer = offer,
|
AcceptDLC(
|
||||||
externalPayoutAddressOpt = None,
|
offer = offer,
|
||||||
externalChangeAddressOpt = None,
|
externalPayoutAddressOpt = None,
|
||||||
peerAddr = peerAddr)
|
externalChangeAddressOpt = None,
|
||||||
|
peerAddr = peerAddr
|
||||||
|
)
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
_ <- setupF
|
_ <- setupF
|
||||||
@ -488,13 +542,16 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture {
|
|||||||
} yield {
|
} yield {
|
||||||
assert(notifications.exists(_ == DLCNodeConnectionInitiated(peerAddr)))
|
assert(notifications.exists(_ == DLCNodeConnectionInitiated(peerAddr)))
|
||||||
assert(notifications.exists(_ == DLCNodeConnectionFailed(peerAddr)))
|
assert(notifications.exists(_ == DLCNodeConnectionFailed(peerAddr)))
|
||||||
assert(notifications.exists(n =>
|
assert(
|
||||||
n match {
|
notifications.exists(n =>
|
||||||
case DLCAcceptFailed((id, error)) =>
|
n match {
|
||||||
id == offer.tlv.tempContractId && error.startsWith(
|
case DLCAcceptFailed((id, error)) =>
|
||||||
"Connection refused")
|
id == offer.tlv.tempContractId && error.startsWith(
|
||||||
case _ => false
|
"Connection refused"
|
||||||
}))
|
)
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ import org.bitcoins.core.protocol.BitcoinAddress
|
|||||||
|
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
|
|
||||||
/** ScalaMock cannot stub traits with protected methods,
|
/** ScalaMock cannot stub traits with protected methods, so we need to stub them
|
||||||
* so we need to stub them manually.
|
* manually.
|
||||||
*/
|
*/
|
||||||
abstract class MockWalletApi extends DLCNeutrinoHDWalletApi {
|
abstract class MockWalletApi extends DLCNeutrinoHDWalletApi {
|
||||||
|
|
||||||
@ -18,7 +18,8 @@ abstract class MockWalletApi extends DLCNeutrinoHDWalletApi {
|
|||||||
override def getDefaultAccount(): Future[AccountDb] = stub
|
override def getDefaultAccount(): Future[AccountDb] = stub
|
||||||
|
|
||||||
override def getDefaultAccountForType(
|
override def getDefaultAccountForType(
|
||||||
addressType: AddressType): Future[AccountDb] = stub
|
addressType: AddressType
|
||||||
|
): Future[AccountDb] = stub
|
||||||
|
|
||||||
private def stub[T] =
|
private def stub[T] =
|
||||||
Future.failed[T](new RuntimeException("Not implemented"))
|
Future.failed[T](new RuntimeException("Not implemented"))
|
||||||
|
@ -27,18 +27,20 @@ import java.util.concurrent.TimeUnit
|
|||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
import scala.concurrent.duration.{DurationInt, FiniteDuration}
|
import scala.concurrent.duration.{DurationInt, FiniteDuration}
|
||||||
|
|
||||||
/** A unified config class for all submodules of Bitcoin-S
|
/** A unified config class for all submodules of Bitcoin-S that accepts
|
||||||
* that accepts configuration. Thanks to implicit definitions
|
* configuration. Thanks to implicit definitions in this case class' companion
|
||||||
* in this case class' companion object an instance
|
* object an instance of this class can be passed in anywhere a wallet, chain
|
||||||
* of this class can be passed in anywhere a wallet,
|
* or node config is required.
|
||||||
* chain or node config is required.
|
|
||||||
*
|
*
|
||||||
* @param directory The data directory of this app configuration
|
* @param directory
|
||||||
* @param confs A sequence of optional configuration overrides
|
* The data directory of this app configuration
|
||||||
|
* @param confs
|
||||||
|
* A sequence of optional configuration overrides
|
||||||
*/
|
*/
|
||||||
case class BitcoinSAppConfig(
|
case class BitcoinSAppConfig(
|
||||||
baseDatadir: Path,
|
baseDatadir: Path,
|
||||||
configOverrides: Vector[Config])(implicit system: ActorSystem)
|
configOverrides: Vector[Config]
|
||||||
|
)(implicit system: ActorSystem)
|
||||||
extends StartStopAsync[AppConfigMarker]
|
extends StartStopAsync[AppConfigMarker]
|
||||||
with BitcoinSLogger {
|
with BitcoinSLogger {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
@ -73,8 +75,8 @@ case class BitcoinSAppConfig(
|
|||||||
/** Initializes the wallet, node and chain projects */
|
/** Initializes the wallet, node and chain projects */
|
||||||
override def start(): Future[StartedBitcoinSAppConfig] = {
|
override def start(): Future[StartedBitcoinSAppConfig] = {
|
||||||
val start = TimeUtil.currentEpochMs
|
val start = TimeUtil.currentEpochMs
|
||||||
//configurations that don't depend on tor startup
|
// configurations that don't depend on tor startup
|
||||||
//start these in parallel as an optimization
|
// start these in parallel as an optimization
|
||||||
val nonTorConfigs = Vector(kmConf, chainConf, walletConf, dlcConf)
|
val nonTorConfigs = Vector(kmConf, chainConf, walletConf, dlcConf)
|
||||||
|
|
||||||
val torConfig = torConf.start()
|
val torConfig = torConf.start()
|
||||||
@ -84,10 +86,10 @@ case class BitcoinSAppConfig(
|
|||||||
val dbConfigsDependentOnTor: Vector[DbManagement] =
|
val dbConfigsDependentOnTor: Vector[DbManagement] =
|
||||||
Vector(nodeConf)
|
Vector(nodeConf)
|
||||||
|
|
||||||
//run migrations here to avoid issues like: https://github.com/bitcoin-s/bitcoin-s/issues/4606
|
// run migrations here to avoid issues like: https://github.com/bitcoin-s/bitcoin-s/issues/4606
|
||||||
//since we don't require tor dependent configs
|
// since we don't require tor dependent configs
|
||||||
//to be fully started before completing the Future returned by this
|
// to be fully started before completing the Future returned by this
|
||||||
//method, we need to run them on their own
|
// method, we need to run them on their own
|
||||||
val migrateTorDependentDbConfigsF =
|
val migrateTorDependentDbConfigsF =
|
||||||
Future.traverse(dbConfigsDependentOnTor)(dbConfig =>
|
Future.traverse(dbConfigsDependentOnTor)(dbConfig =>
|
||||||
Future(dbConfig.migrate()))
|
Future(dbConfig.migrate()))
|
||||||
@ -109,7 +111,8 @@ case class BitcoinSAppConfig(
|
|||||||
_ <- startedNonTorConfigsF
|
_ <- startedNonTorConfigsF
|
||||||
} yield {
|
} yield {
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Done starting BitcoinSAppConfig, it took=${TimeUtil.currentEpochMs - start}ms")
|
s"Done starting BitcoinSAppConfig, it took=${TimeUtil.currentEpochMs - start}ms"
|
||||||
|
)
|
||||||
StartedBitcoinSAppConfig(startedTorDependentConfigsF.map(_ => ()))
|
StartedBitcoinSAppConfig(startedTorDependentConfigsF.map(_ => ()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,9 +135,11 @@ case class BitcoinSAppConfig(
|
|||||||
/** The underlying config the result of our fields derive from */
|
/** The underlying config the result of our fields derive from */
|
||||||
lazy val config: Config = {
|
lazy val config: Config = {
|
||||||
val finalConfig =
|
val finalConfig =
|
||||||
AppConfig.getBaseConfig(baseDatadir = baseDatadir,
|
AppConfig.getBaseConfig(
|
||||||
DEFAULT_BITCOIN_S_CONF_FILE,
|
baseDatadir = baseDatadir,
|
||||||
configOverrides)
|
DEFAULT_BITCOIN_S_CONF_FILE,
|
||||||
|
configOverrides
|
||||||
|
)
|
||||||
val resolved = finalConfig.resolve()
|
val resolved = finalConfig.resolve()
|
||||||
|
|
||||||
resolved.checkValid(ConfigFactory.defaultReference(), "bitcoin-s")
|
resolved.checkValid(ConfigFactory.defaultReference(), "bitcoin-s")
|
||||||
@ -146,8 +151,8 @@ case class BitcoinSAppConfig(
|
|||||||
|
|
||||||
def wsPort: Int = config.getIntOrElse("bitcoin-s.server.wsport", 19999)
|
def wsPort: Int = config.getIntOrElse("bitcoin-s.server.wsport", 19999)
|
||||||
|
|
||||||
/** How long until we forcefully terminate connections to the server
|
/** How long until we forcefully terminate connections to the server when
|
||||||
* when shutting down the server
|
* shutting down the server
|
||||||
*/
|
*/
|
||||||
def terminationDeadline: FiniteDuration = {
|
def terminationDeadline: FiniteDuration = {
|
||||||
val opt = config.getDurationOpt("bitcoin-s.server.termination-deadline")
|
val opt = config.getDurationOpt("bitcoin-s.server.termination-deadline")
|
||||||
@ -157,9 +162,10 @@ case class BitcoinSAppConfig(
|
|||||||
new FiniteDuration(duration.toNanos, TimeUnit.NANOSECONDS)
|
new FiniteDuration(duration.toNanos, TimeUnit.NANOSECONDS)
|
||||||
} else {
|
} else {
|
||||||
sys.error(
|
sys.error(
|
||||||
s"Can only have a finite duration for termination deadline, got=$duration")
|
s"Can only have a finite duration for termination deadline, got=$duration"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
case None => 5.seconds //5 seconds by default
|
case None => 5.seconds // 5 seconds by default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,13 +196,14 @@ case class BitcoinSAppConfig(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Implicit conversions that allow a unified configuration
|
/** Implicit conversions that allow a unified configuration to be passed in
|
||||||
* to be passed in wherever a specializes one is required
|
* wherever a specializes one is required
|
||||||
*/
|
*/
|
||||||
object BitcoinSAppConfig extends BitcoinSLogger {
|
object BitcoinSAppConfig extends BitcoinSLogger {
|
||||||
|
|
||||||
def fromConfig(config: Config)(implicit
|
def fromConfig(
|
||||||
system: ActorSystem): BitcoinSAppConfig = {
|
config: Config
|
||||||
|
)(implicit system: ActorSystem): BitcoinSAppConfig = {
|
||||||
val configDataDir: Path = Paths.get(config.getString("bitcoin-s.datadir"))
|
val configDataDir: Path = Paths.get(config.getString("bitcoin-s.datadir"))
|
||||||
BitcoinSAppConfig(configDataDir, Vector(config))
|
BitcoinSAppConfig(configDataDir, Vector(config))
|
||||||
}
|
}
|
||||||
@ -206,33 +213,36 @@ object BitcoinSAppConfig extends BitcoinSLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def fromDatadir(datadir: Path, confs: Config*)(implicit
|
def fromDatadir(datadir: Path, confs: Config*)(implicit
|
||||||
system: ActorSystem): BitcoinSAppConfig = {
|
system: ActorSystem
|
||||||
|
): BitcoinSAppConfig = {
|
||||||
BitcoinSAppConfig(datadir, confs.toVector)
|
BitcoinSAppConfig(datadir, confs.toVector)
|
||||||
}
|
}
|
||||||
|
|
||||||
def fromDatadirWithServerArgs(
|
def fromDatadirWithServerArgs(
|
||||||
datadir: Path,
|
datadir: Path,
|
||||||
serverArgsParser: ServerArgParser)(implicit
|
serverArgsParser: ServerArgParser
|
||||||
system: ActorSystem): BitcoinSAppConfig = {
|
)(implicit system: ActorSystem): BitcoinSAppConfig = {
|
||||||
fromDatadir(datadir, serverArgsParser.toConfig)
|
fromDatadir(datadir, serverArgsParser.toConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Constructs an app configuration from the default Bitcoin-S
|
/** Constructs an app configuration from the default Bitcoin-S data directory
|
||||||
* data directory and given list of configuration overrides.
|
* and given list of configuration overrides.
|
||||||
*/
|
*/
|
||||||
def fromDefaultDatadir(confs: Config*)(implicit
|
def fromDefaultDatadir(confs: Config*)(implicit
|
||||||
system: ActorSystem): BitcoinSAppConfig =
|
system: ActorSystem
|
||||||
|
): BitcoinSAppConfig =
|
||||||
BitcoinSAppConfig(AppConfig.DEFAULT_BITCOIN_S_DATADIR, confs.toVector)
|
BitcoinSAppConfig(AppConfig.DEFAULT_BITCOIN_S_DATADIR, confs.toVector)
|
||||||
|
|
||||||
def fromDefaultDatadirWithBundleConf(confs: Vector[Config] = Vector.empty)(
|
def fromDefaultDatadirWithBundleConf(
|
||||||
implicit system: ActorSystem): BitcoinSAppConfig = {
|
confs: Vector[Config] = Vector.empty
|
||||||
|
)(implicit system: ActorSystem): BitcoinSAppConfig = {
|
||||||
fromDatadirWithBundleConf(AppConfig.DEFAULT_BITCOIN_S_DATADIR, confs)
|
fromDatadirWithBundleConf(AppConfig.DEFAULT_BITCOIN_S_DATADIR, confs)
|
||||||
}
|
}
|
||||||
|
|
||||||
def fromDatadirWithBundleConf(
|
def fromDatadirWithBundleConf(
|
||||||
datadir: Path,
|
datadir: Path,
|
||||||
confs: Vector[Config] = Vector.empty)(implicit
|
confs: Vector[Config] = Vector.empty
|
||||||
system: ActorSystem): BitcoinSAppConfig = {
|
)(implicit system: ActorSystem): BitcoinSAppConfig = {
|
||||||
val baseConf: BitcoinSAppConfig =
|
val baseConf: BitcoinSAppConfig =
|
||||||
fromDatadir(datadir, confs: _*)
|
fromDatadir(datadir, confs: _*)
|
||||||
|
|
||||||
@ -250,22 +260,20 @@ object BitcoinSAppConfig extends BitcoinSLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Resolve BitcoinSAppConfig in the following order of precedence
|
/** Resolve BitcoinSAppConfig in the following order of precedence
|
||||||
* 1. Server args
|
* 1. Server args 2. bitcoin-s-bundle.conf 3. bitcoin-s.conf 4.
|
||||||
* 2. bitcoin-s-bundle.conf
|
* application.conf 5. reference.conf
|
||||||
* 3. bitcoin-s.conf
|
|
||||||
* 4. application.conf
|
|
||||||
* 5. reference.conf
|
|
||||||
*/
|
*/
|
||||||
def fromDatadirWithBundleConfWithServerArgs(
|
def fromDatadirWithBundleConfWithServerArgs(
|
||||||
datadir: Path,
|
datadir: Path,
|
||||||
serverArgParser: ServerArgParser)(implicit
|
serverArgParser: ServerArgParser
|
||||||
system: ActorSystem): BitcoinSAppConfig = {
|
)(implicit system: ActorSystem): BitcoinSAppConfig = {
|
||||||
fromDatadirWithBundleConf(datadir, Vector(serverArgParser.toConfig))
|
fromDatadirWithBundleConf(datadir, Vector(serverArgParser.toConfig))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a BitcoinSAppConfig the the given daemon args to a server */
|
/** Creates a BitcoinSAppConfig the the given daemon args to a server */
|
||||||
def fromDefaultDatadirWithServerArgs(serverArgParser: ServerArgParser)(
|
def fromDefaultDatadirWithServerArgs(
|
||||||
implicit system: ActorSystem): BitcoinSAppConfig = {
|
serverArgParser: ServerArgParser
|
||||||
|
)(implicit system: ActorSystem): BitcoinSAppConfig = {
|
||||||
val config = serverArgParser.toConfig
|
val config = serverArgParser.toConfig
|
||||||
fromConfig(config)
|
fromConfig(config)
|
||||||
}
|
}
|
||||||
|
@ -51,8 +51,8 @@ import scala.concurrent.{Await, Future, Promise}
|
|||||||
|
|
||||||
class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
||||||
override val system: ActorSystem,
|
override val system: ActorSystem,
|
||||||
val conf: BitcoinSAppConfig)
|
val conf: BitcoinSAppConfig
|
||||||
extends BitcoinSServerRunner[WalletHolder] {
|
) extends BitcoinSServerRunner[WalletHolder] {
|
||||||
|
|
||||||
implicit lazy val nodeConf: NodeAppConfig = conf.nodeConf
|
implicit lazy val nodeConf: NodeAppConfig = conf.nodeConf
|
||||||
implicit lazy val chainConf: ChainAppConfig = conf.chainConf
|
implicit lazy val chainConf: ChainAppConfig = conf.chainConf
|
||||||
@ -69,16 +69,18 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
logger.info(s"Start on network $network")
|
logger.info(s"Start on network $network")
|
||||||
|
|
||||||
startedConfigF.failed.foreach { err =>
|
startedConfigF.failed.foreach { err =>
|
||||||
logger.error(s"Failed to initialize configuration for BitcoinServerMain",
|
logger.error(
|
||||||
err)
|
s"Failed to initialize configuration for BitcoinServerMain",
|
||||||
|
err
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
startedConfig <- startedConfigF
|
startedConfig <- startedConfigF
|
||||||
chainApi = ChainHandler.fromDatabase()
|
chainApi = ChainHandler.fromDatabase()
|
||||||
nodeType = nodeConf.nodeType
|
nodeType = nodeConf.nodeType
|
||||||
//on server startup we assume we are out of sync with the bitcoin network
|
// on server startup we assume we are out of sync with the bitcoin network
|
||||||
//so we set this flag to true.
|
// so we set this flag to true.
|
||||||
_ <- initializeChainState(chainApi, nodeType)
|
_ <- initializeChainState(chainApi, nodeType)
|
||||||
start <- {
|
start <- {
|
||||||
nodeType match {
|
nodeType match {
|
||||||
@ -90,21 +92,23 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
}
|
}
|
||||||
} yield {
|
} yield {
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Done start BitcoinSServerMain, it took=${TimeUtil.currentEpochMs - startTime}ms")
|
s"Done start BitcoinSServerMain, it took=${TimeUtil.currentEpochMs - startTime}ms"
|
||||||
|
)
|
||||||
start
|
start
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def initializeChainState(
|
private def initializeChainState(
|
||||||
chainHandler: ChainHandler,
|
chainHandler: ChainHandler,
|
||||||
nodeType: NodeType): Future[Unit] = {
|
nodeType: NodeType
|
||||||
|
): Future[Unit] = {
|
||||||
val syncF = chainHandler.setSyncing(true)
|
val syncF = chainHandler.setSyncing(true)
|
||||||
val blockCountF = chainHandler.getBlockCount()
|
val blockCountF = chainHandler.getBlockCount()
|
||||||
nodeType match {
|
nodeType match {
|
||||||
case NodeType.NeutrinoNode =>
|
case NodeType.NeutrinoNode =>
|
||||||
blockCountF.flatMap { blockCount =>
|
blockCountF.flatMap { blockCount =>
|
||||||
if (blockCount == 0) {
|
if (blockCount == 0) {
|
||||||
//means we are starting a fresh node, set IBD to true
|
// means we are starting a fresh node, set IBD to true
|
||||||
chainHandler
|
chainHandler
|
||||||
.setIBD(true)
|
.setIBD(true)
|
||||||
.map(_ => ())
|
.map(_ => ())
|
||||||
@ -113,11 +117,12 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case NodeType.BitcoindBackend =>
|
case NodeType.BitcoindBackend =>
|
||||||
//don't need to do anything as we outsource chain management to bitcoind
|
// don't need to do anything as we outsource chain management to bitcoind
|
||||||
syncF.map(_ => ())
|
syncF.map(_ => ())
|
||||||
case NodeType.FullNode =>
|
case NodeType.FullNode =>
|
||||||
sys.error(
|
sys.error(
|
||||||
s"Full not is not implemented, not sure what to do with chainstate")
|
s"Full not is not implemented, not sure what to do with chainstate"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +152,7 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
_ = logger.info(s"Stopped ${nodeConf.nodeType.shortName} node")
|
_ = logger.info(s"Stopped ${nodeConf.nodeType.shortName} node")
|
||||||
} yield {
|
} yield {
|
||||||
resetState()
|
resetState()
|
||||||
//return empty wallet holder
|
// return empty wallet holder
|
||||||
WalletHolder.empty
|
WalletHolder.empty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,21 +165,24 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Start the bitcoin-s wallet server with a neutrino backend
|
/** Start the bitcoin-s wallet server with a neutrino backend
|
||||||
* @param startedTorConfigF a future that is completed when tor is fully started
|
* @param startedTorConfigF
|
||||||
|
* a future that is completed when tor is fully started
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
def startBitcoinSBackend(
|
def startBitcoinSBackend(
|
||||||
startedTorConfigF: Future[Unit]): Future[WalletHolder] = {
|
startedTorConfigF: Future[Unit]
|
||||||
|
): Future[WalletHolder] = {
|
||||||
logger.info(s"startBitcoinSBackend()")
|
logger.info(s"startBitcoinSBackend()")
|
||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
|
|
||||||
val chainApi = ChainHandler.fromDatabase()
|
val chainApi = ChainHandler.fromDatabase()
|
||||||
val creationTime: Instant = conf.walletConf.creationTime
|
val creationTime: Instant = conf.walletConf.creationTime
|
||||||
|
|
||||||
//get a node that isn't started
|
// get a node that isn't started
|
||||||
val nodeF = nodeConf.createNode(
|
val nodeF = nodeConf.createNode(
|
||||||
peers = nodeConf.peers,
|
peers = nodeConf.peers,
|
||||||
walletCreationTimeOpt = Some(creationTime))(chainConf, system)
|
walletCreationTimeOpt = Some(creationTime)
|
||||||
|
)(chainConf, system)
|
||||||
|
|
||||||
val defaultApi =
|
val defaultApi =
|
||||||
MempoolSpaceProvider(HourFeeTarget, network, torConf.socks5ProxyParams)
|
MempoolSpaceProvider(HourFeeTarget, network, torConf.socks5ProxyParams)
|
||||||
@ -183,17 +191,20 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
conf.walletConf.feeProviderNameOpt,
|
conf.walletConf.feeProviderNameOpt,
|
||||||
conf.walletConf.feeProviderTargetOpt,
|
conf.walletConf.feeProviderTargetOpt,
|
||||||
torConf.socks5ProxyParams,
|
torConf.socks5ProxyParams,
|
||||||
network)
|
network
|
||||||
//get our wallet
|
)
|
||||||
|
// get our wallet
|
||||||
val walletHolder = WalletHolder.empty
|
val walletHolder = WalletHolder.empty
|
||||||
val neutrinoWalletLoaderF = {
|
val neutrinoWalletLoaderF = {
|
||||||
for {
|
for {
|
||||||
node <- nodeF
|
node <- nodeF
|
||||||
} yield {
|
} yield {
|
||||||
val l = DLCWalletNeutrinoBackendLoader(walletHolder,
|
val l = DLCWalletNeutrinoBackendLoader(
|
||||||
chainApi,
|
walletHolder,
|
||||||
nodeApi = node,
|
chainApi,
|
||||||
feeRateApi = feeProvider)
|
nodeApi = node,
|
||||||
|
feeRateApi = feeProvider
|
||||||
|
)
|
||||||
walletLoaderApiOpt = Some(l)
|
walletLoaderApiOpt = Some(l)
|
||||||
l
|
l
|
||||||
}
|
}
|
||||||
@ -208,13 +219,13 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
torConf.addCallbacks(torCallbacks)
|
torConf.addCallbacks(torCallbacks)
|
||||||
|
|
||||||
val isTorStartedF = if (torConf.torProvided) {
|
val isTorStartedF = if (torConf.torProvided) {
|
||||||
//if tor is provided we need to execute the tor started callback immediately
|
// if tor is provided we need to execute the tor started callback immediately
|
||||||
torConf.callBacks.executeOnTorStarted()
|
torConf.callBacks.executeOnTorStarted()
|
||||||
} else {
|
} else {
|
||||||
Future.unit
|
Future.unit
|
||||||
}
|
}
|
||||||
val startedNodeF = {
|
val startedNodeF = {
|
||||||
//can't start connecting to peers until tor is done starting
|
// can't start connecting to peers until tor is done starting
|
||||||
for {
|
for {
|
||||||
_ <- startedTorConfigF
|
_ <- startedTorConfigF
|
||||||
_ <- isTorStartedF
|
_ <- isTorStartedF
|
||||||
@ -229,7 +240,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
_ <- startedNodeF
|
_ <- startedNodeF
|
||||||
walletWithConfigs <- neutrinoWalletLoader.load(
|
walletWithConfigs <- neutrinoWalletLoader.load(
|
||||||
walletNameOpt = walletNameOpt,
|
walletNameOpt = walletNameOpt,
|
||||||
aesPasswordOpt = conf.walletConf.aesPasswordOpt)
|
aesPasswordOpt = conf.walletConf.aesPasswordOpt
|
||||||
|
)
|
||||||
} yield {
|
} yield {
|
||||||
walletWithConfigs
|
walletWithConfigs
|
||||||
}
|
}
|
||||||
@ -250,7 +262,7 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
} yield dlcNode
|
} yield dlcNode
|
||||||
}
|
}
|
||||||
|
|
||||||
//start our http server now that we are synced
|
// start our http server now that we are synced
|
||||||
val startedF = for {
|
val startedF = for {
|
||||||
_ <- configuredWalletF
|
_ <- configuredWalletF
|
||||||
_ <- startHttpServer(
|
_ <- startHttpServer(
|
||||||
@ -265,16 +277,18 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
_ = {
|
_ = {
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Starting ${nodeConf.nodeType.shortName} node sync, it took=${System
|
s"Starting ${nodeConf.nodeType.shortName} node sync, it took=${System
|
||||||
.currentTimeMillis() - start}ms")
|
.currentTimeMillis() - start}ms"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
//make sure callbacks are registered before we start sync
|
// make sure callbacks are registered before we start sync
|
||||||
_ <- callbacksF
|
_ <- callbacksF
|
||||||
node <- startedNodeF
|
node <- startedNodeF
|
||||||
_ <- startedTorConfigF
|
_ <- startedTorConfigF
|
||||||
} yield {
|
} yield {
|
||||||
nodeOpt = Some(node)
|
nodeOpt = Some(node)
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Done starting Main! It took ${System.currentTimeMillis() - start}ms")
|
s"Done starting Main! It took ${System.currentTimeMillis() - start}ms"
|
||||||
|
)
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +302,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
wsQueue: SourceQueueWithComplete[WsNotification[_]],
|
wsQueue: SourceQueueWithComplete[WsNotification[_]],
|
||||||
chainApi: ChainApi,
|
chainApi: ChainApi,
|
||||||
walletConf: WalletAppConfig,
|
walletConf: WalletAppConfig,
|
||||||
dlcConf: DLCAppConfig): Unit = {
|
dlcConf: DLCAppConfig
|
||||||
|
): Unit = {
|
||||||
val chainCallbacks = WebsocketUtil.buildChainCallbacks(wsQueue, chainApi)
|
val chainCallbacks = WebsocketUtil.buildChainCallbacks(wsQueue, chainApi)
|
||||||
chainConf.addCallbacks(chainCallbacks)
|
chainConf.addCallbacks(chainCallbacks)
|
||||||
|
|
||||||
@ -308,10 +323,11 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns blockchain info, in case of [[InWarmUp]] exception it retries.
|
/** Returns blockchain info, in case of [[InWarmUp]] exception it retries.
|
||||||
*/
|
*/
|
||||||
private def getBlockChainInfo(
|
private def getBlockChainInfo(
|
||||||
client: BitcoindRpcClient): Future[GetBlockChainInfoResult] = {
|
client: BitcoindRpcClient
|
||||||
|
): Future[GetBlockChainInfoResult] = {
|
||||||
val promise = Promise[GetBlockChainInfoResult]()
|
val promise = Promise[GetBlockChainInfoResult]()
|
||||||
val interval = 1.second
|
val interval = 1.second
|
||||||
val maxTries = 12
|
val maxTries = 12
|
||||||
@ -346,11 +362,13 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
private[this] var nodeOpt: Option[Node] = None
|
private[this] var nodeOpt: Option[Node] = None
|
||||||
|
|
||||||
/** Start the bitcoin-s wallet server with a bitcoind backend
|
/** Start the bitcoin-s wallet server with a bitcoind backend
|
||||||
* @param startedTorConfigF a future that is completed when tor is fully started
|
* @param startedTorConfigF
|
||||||
|
* a future that is completed when tor is fully started
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private def startBitcoindBackend(
|
private def startBitcoindBackend(
|
||||||
startedTorConfigF: Future[Unit]): Future[WalletHolder] = {
|
startedTorConfigF: Future[Unit]
|
||||||
|
): Future[WalletHolder] = {
|
||||||
logger.info(s"startBitcoindBackend()")
|
logger.info(s"startBitcoindBackend()")
|
||||||
val bitcoindF = for {
|
val bitcoindF = for {
|
||||||
client <- bitcoindRpcConf.clientF
|
client <- bitcoindRpcConf.clientF
|
||||||
@ -365,7 +383,7 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
val torCallbacks = WebsocketUtil.buildTorCallbacks(wsQueue)
|
val torCallbacks = WebsocketUtil.buildTorCallbacks(wsQueue)
|
||||||
val _ = torConf.addCallbacks(torCallbacks)
|
val _ = torConf.addCallbacks(torCallbacks)
|
||||||
val isTorStartedF = if (torConf.torProvided) {
|
val isTorStartedF = if (torConf.torProvided) {
|
||||||
//if tor is provided we need to emit a tor started event immediately
|
// if tor is provided we need to emit a tor started event immediately
|
||||||
torConf.callBacks.executeOnTorStarted()
|
torConf.callBacks.executeOnTorStarted()
|
||||||
} else {
|
} else {
|
||||||
Future.unit
|
Future.unit
|
||||||
@ -373,7 +391,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
val walletNameF = for {
|
val walletNameF = for {
|
||||||
lastLoadedWallet <- getLastLoadedWalletName()
|
lastLoadedWallet <- getLastLoadedWalletName()
|
||||||
walletName = lastLoadedWallet.getOrElse(
|
walletName = lastLoadedWallet.getOrElse(
|
||||||
WalletAppConfig.DEFAULT_WALLET_NAME)
|
WalletAppConfig.DEFAULT_WALLET_NAME
|
||||||
|
)
|
||||||
} yield walletName
|
} yield walletName
|
||||||
|
|
||||||
val walletHolder = WalletHolder.empty
|
val walletHolder = WalletHolder.empty
|
||||||
@ -388,7 +407,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
} yield BitcoindRpcBackendUtil.buildBitcoindNodeApi(
|
} yield BitcoindRpcBackendUtil.buildBitcoindNodeApi(
|
||||||
bitcoind,
|
bitcoind,
|
||||||
Future.successful(walletHolder),
|
Future.successful(walletHolder),
|
||||||
Some(chainCallbacks))
|
Some(chainCallbacks)
|
||||||
|
)
|
||||||
|
|
||||||
val feeProviderF = bitcoindF.map { bitcoind =>
|
val feeProviderF = bitcoindF.map { bitcoind =>
|
||||||
FeeProviderFactory.getFeeProviderOrElse(
|
FeeProviderFactory.getFeeProviderOrElse(
|
||||||
@ -406,10 +426,12 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
nodeApi <- nodeApiF
|
nodeApi <- nodeApiF
|
||||||
feeProvider <- feeProviderF
|
feeProvider <- feeProviderF
|
||||||
} yield {
|
} yield {
|
||||||
val l = DLCWalletBitcoindBackendLoader(walletHolder = walletHolder,
|
val l = DLCWalletBitcoindBackendLoader(
|
||||||
bitcoind = bitcoind,
|
walletHolder = walletHolder,
|
||||||
nodeApi = nodeApi,
|
bitcoind = bitcoind,
|
||||||
feeProvider = feeProvider)
|
nodeApi = nodeApi,
|
||||||
|
feeProvider = feeProvider
|
||||||
|
)
|
||||||
|
|
||||||
walletLoaderApiOpt = Some(l)
|
walletLoaderApiOpt = Some(l)
|
||||||
l
|
l
|
||||||
@ -421,8 +443,10 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
_ <- isTorStartedF
|
_ <- isTorStartedF
|
||||||
loadWalletApi <- loadWalletApiF
|
loadWalletApi <- loadWalletApiF
|
||||||
walletName <- walletNameF
|
walletName <- walletNameF
|
||||||
result <- loadWalletApi.load(Some(walletName),
|
result <- loadWalletApi.load(
|
||||||
conf.walletConf.aesPasswordOpt)
|
Some(walletName),
|
||||||
|
conf.walletConf.aesPasswordOpt
|
||||||
|
)
|
||||||
} yield result
|
} yield result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,7 +466,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
bitcoindNetwork = blockchainInfo.chain
|
bitcoindNetwork = blockchainInfo.chain
|
||||||
_ = require(
|
_ = require(
|
||||||
bitcoindNetwork == network,
|
bitcoindNetwork == network,
|
||||||
s"bitcoind ($bitcoindNetwork) on different network than wallet ($network)")
|
s"bitcoind ($bitcoindNetwork) on different network than wallet ($network)"
|
||||||
|
)
|
||||||
_ <- startHttpServer(
|
_ <- startHttpServer(
|
||||||
nodeApiF = Future.successful(bitcoind),
|
nodeApiF = Future.successful(bitcoind),
|
||||||
chainApi = bitcoind,
|
chainApi = bitcoind,
|
||||||
@ -453,8 +478,10 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
wsSource = wsSource
|
wsSource = wsSource
|
||||||
)
|
)
|
||||||
walletName <- walletNameF
|
walletName <- walletNameF
|
||||||
walletCallbacks = WebsocketUtil.buildWalletCallbacks(wsQueue,
|
walletCallbacks = WebsocketUtil.buildWalletCallbacks(
|
||||||
walletName)
|
wsQueue,
|
||||||
|
walletName
|
||||||
|
)
|
||||||
chainCallbacks <- chainCallbacksF
|
chainCallbacks <- chainCallbacksF
|
||||||
(wallet, walletConfig, dlcConfig) <- walletF
|
(wallet, walletConfig, dlcConfig) <- walletF
|
||||||
_ = walletConfig.addCallbacks(walletCallbacks)
|
_ = walletConfig.addCallbacks(walletCallbacks)
|
||||||
@ -462,7 +489,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
bitcoindSyncState <- syncWalletWithBitcoindAndStartPolling(
|
bitcoindSyncState <- syncWalletWithBitcoindAndStartPolling(
|
||||||
bitcoind,
|
bitcoind,
|
||||||
wallet,
|
wallet,
|
||||||
Some(chainCallbacks))
|
Some(chainCallbacks)
|
||||||
|
)
|
||||||
_ = {
|
_ = {
|
||||||
bitcoindSyncStateOpt = Some(bitcoindSyncState)
|
bitcoindSyncStateOpt = Some(bitcoindSyncState)
|
||||||
}
|
}
|
||||||
@ -477,9 +505,9 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//don't return the Future that represents the full syncing of the wallet with bitcoind
|
// don't return the Future that represents the full syncing of the wallet with bitcoind
|
||||||
for {
|
for {
|
||||||
_ <- bitcoindSyncStateF //drop nested Future here
|
_ <- bitcoindSyncStateF // drop nested Future here
|
||||||
walletHolder <- walletF.map(_._1)
|
walletHolder <- walletF.map(_._1)
|
||||||
} yield walletHolder
|
} yield walletHolder
|
||||||
}
|
}
|
||||||
@ -493,9 +521,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
dlcNodeF: Future[DLCNode],
|
dlcNodeF: Future[DLCNode],
|
||||||
torConfStarted: Future[Unit],
|
torConfStarted: Future[Unit],
|
||||||
serverCmdLineArgs: ServerArgParser,
|
serverCmdLineArgs: ServerArgParser,
|
||||||
wsSource: Source[WsNotification[_], NotUsed])(implicit
|
wsSource: Source[WsNotification[_], NotUsed]
|
||||||
system: ActorSystem,
|
)(implicit system: ActorSystem, conf: BitcoinSAppConfig): Future[Server] = {
|
||||||
conf: BitcoinSAppConfig): Future[Server] = {
|
|
||||||
implicit val nodeConf: NodeAppConfig = conf.nodeConf
|
implicit val nodeConf: NodeAppConfig = conf.nodeConf
|
||||||
implicit val walletConf: WalletAppConfig = conf.walletConf
|
implicit val walletConf: WalletAppConfig = conf.walletConf
|
||||||
|
|
||||||
@ -516,7 +543,7 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
Future.successful(commonRoutes),
|
Future.successful(commonRoutes),
|
||||||
Future.successful(coreRoutes),
|
Future.successful(coreRoutes),
|
||||||
Future.successful(chainRoutes),
|
Future.successful(chainRoutes),
|
||||||
//dependent on tor, slow start up
|
// dependent on tor, slow start up
|
||||||
walletRoutesF,
|
walletRoutesF,
|
||||||
nodeRoutesF,
|
nodeRoutesF,
|
||||||
dlcRoutesF
|
dlcRoutesF
|
||||||
@ -543,13 +570,15 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
val server = {
|
val server = {
|
||||||
serverCmdLineArgs.rpcPortOpt match {
|
serverCmdLineArgs.rpcPortOpt match {
|
||||||
case Some(rpcport) =>
|
case Some(rpcport) =>
|
||||||
Server(conf = nodeConf,
|
Server(
|
||||||
handlersF = handlers,
|
conf = nodeConf,
|
||||||
rpcbindOpt = rpcBindConfOpt,
|
handlersF = handlers,
|
||||||
rpcport = rpcport,
|
rpcbindOpt = rpcBindConfOpt,
|
||||||
rpcPassword = conf.rpcPassword,
|
rpcport = rpcport,
|
||||||
wsConfigOpt = Some(wsServerConfig),
|
rpcPassword = conf.rpcPassword,
|
||||||
wsSource)
|
wsConfigOpt = Some(wsServerConfig),
|
||||||
|
wsSource
|
||||||
|
)
|
||||||
case None =>
|
case None =>
|
||||||
Server(
|
Server(
|
||||||
conf = nodeConf,
|
conf = nodeConf,
|
||||||
@ -570,29 +599,33 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Syncs the bitcoin-s wallet against bitcoind and then
|
/** Syncs the bitcoin-s wallet against bitcoind and then starts rpc polling if
|
||||||
* starts rpc polling if zmq isn't enabled, otherwise it starts zmq polling.
|
* zmq isn't enabled, otherwise it starts zmq polling.
|
||||||
*
|
*
|
||||||
* The key thing this helper method does is it logs errors based on the
|
* The key thing this helper method does is it logs errors based on the
|
||||||
* future returned by this method. This is needed because we don't want
|
* future returned by this method. This is needed because we don't want to
|
||||||
* to block the rest of the application from starting if we have to
|
* block the rest of the application from starting if we have to do a ton of
|
||||||
* do a ton of syncing. However, we don't want to swallow
|
* syncing. However, we don't want to swallow exceptions thrown by this
|
||||||
* exceptions thrown by this method.
|
* method.
|
||||||
* @return the [[Cancellable]] representing the schedule job that polls the mempool. You can call .cancel() to stop this
|
* @return
|
||||||
|
* the [[Cancellable]] representing the schedule job that polls the
|
||||||
|
* mempool. You can call .cancel() to stop this
|
||||||
*/
|
*/
|
||||||
private def syncWalletWithBitcoindAndStartPolling(
|
private def syncWalletWithBitcoindAndStartPolling(
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
wallet: NeutrinoHDWalletApi,
|
wallet: NeutrinoHDWalletApi,
|
||||||
chainCallbacksOpt: Option[ChainCallbacks]): Future[BitcoindSyncState] = {
|
chainCallbacksOpt: Option[ChainCallbacks]
|
||||||
|
): Future[BitcoindSyncState] = {
|
||||||
val f = for {
|
val f = for {
|
||||||
_ <- handlePotentialBitcoindLostBlock(bitcoind, wallet)
|
_ <- handlePotentialBitcoindLostBlock(bitcoind, wallet)
|
||||||
syncF = BitcoindRpcBackendUtil.syncWalletToBitcoind(
|
syncF = BitcoindRpcBackendUtil.syncWalletToBitcoind(
|
||||||
bitcoind,
|
bitcoind,
|
||||||
wallet,
|
wallet,
|
||||||
chainCallbacksOpt)(system)
|
chainCallbacksOpt
|
||||||
|
)(system)
|
||||||
_ = syncF.map(_ => wallet.updateUtxoPendingStates())
|
_ = syncF.map(_ => wallet.updateUtxoPendingStates())
|
||||||
|
|
||||||
//don't start polling until initial sync is done
|
// don't start polling until initial sync is done
|
||||||
pollingCancellable <- syncF.flatMap { _ =>
|
pollingCancellable <- syncF.flatMap { _ =>
|
||||||
if (bitcoindRpcConf.zmqConfig == ZmqConfig.empty) {
|
if (bitcoindRpcConf.zmqConfig == ZmqConfig.empty) {
|
||||||
val blockingPollingCancellable = BitcoindRpcBackendUtil
|
val blockingPollingCancellable = BitcoindRpcBackendUtil
|
||||||
@ -603,15 +636,18 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
.executeOnTxReceivedCallbacks(tx)
|
.executeOnTxReceivedCallbacks(tx)
|
||||||
}
|
}
|
||||||
val combinedCancellable =
|
val combinedCancellable =
|
||||||
BitcoindPollingCancellable(blockingPollingCancellable,
|
BitcoindPollingCancellable(
|
||||||
mempoolCancellable)
|
blockingPollingCancellable,
|
||||||
|
mempoolCancellable
|
||||||
|
)
|
||||||
|
|
||||||
Future.successful(combinedCancellable)
|
Future.successful(combinedCancellable)
|
||||||
} else {
|
} else {
|
||||||
Future {
|
Future {
|
||||||
BitcoindRpcBackendUtil.startZMQWalletCallbacks(
|
BitcoindRpcBackendUtil.startZMQWalletCallbacks(
|
||||||
wallet,
|
wallet,
|
||||||
bitcoindRpcConf.zmqConfig)
|
bitcoindRpcConf.zmqConfig
|
||||||
|
)
|
||||||
BitcoindPollingCancellabe.none
|
BitcoindPollingCancellabe.none
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -624,13 +660,15 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
f
|
f
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Surprisingly on some OSes like umbrel bitcoind can lose blocks during the shutdown process
|
/** Surprisingly on some OSes like umbrel bitcoind can lose blocks during the
|
||||||
* This means next time we boot up, our wallet will have more blocks than bitcoind!
|
* shutdown process This means next time we boot up, our wallet will have
|
||||||
* Eventually bitcoind will synchrnoize with the network. This waits until bitcoind is synced
|
* more blocks than bitcoind! Eventually bitcoind will synchrnoize with the
|
||||||
|
* network. This waits until bitcoind is synced
|
||||||
*/
|
*/
|
||||||
private def handlePotentialBitcoindLostBlock(
|
private def handlePotentialBitcoindLostBlock(
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
wallet: WalletApi): Future[Unit] = {
|
wallet: WalletApi
|
||||||
|
): Future[Unit] = {
|
||||||
AsyncUtil.retryUntilSatisfiedF(
|
AsyncUtil.retryUntilSatisfiedF(
|
||||||
conditionF = { () =>
|
conditionF = { () =>
|
||||||
for {
|
for {
|
||||||
@ -645,21 +683,22 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Builds a websocket queue that you can feed elements to.
|
/** Builds a websocket queue that you can feed elements to. The Source can be
|
||||||
* The Source can be wired up with Directives.handleWebSocketMessages
|
* wired up with Directives.handleWebSocketMessages to create a flow that
|
||||||
* to create a flow that emits websocket messages
|
* emits websocket messages
|
||||||
*/
|
*/
|
||||||
private def buildWsSource: (
|
private def buildWsSource: (
|
||||||
SourceQueueWithComplete[WsNotification[_]],
|
SourceQueueWithComplete[WsNotification[_]],
|
||||||
Source[WsNotification[_], NotUsed]) = {
|
Source[WsNotification[_], NotUsed]
|
||||||
|
) = {
|
||||||
val maxBufferSize: Int = 25
|
val maxBufferSize: Int = 25
|
||||||
|
|
||||||
/** This will queue [[maxBufferSize]] elements in the queue. Once the buffer size is reached,
|
/** This will queue [[maxBufferSize]] elements in the queue. Once the buffer
|
||||||
* we will drop the first element in the buffer
|
* size is reached, we will drop the first element in the buffer
|
||||||
*/
|
*/
|
||||||
val tuple = {
|
val tuple = {
|
||||||
//from: https://github.com/akka/akka-http/issues/3039#issuecomment-610263181
|
// from: https://github.com/akka/akka-http/issues/3039#issuecomment-610263181
|
||||||
//the BroadcastHub.sink is needed to avoid these errors
|
// the BroadcastHub.sink is needed to avoid these errors
|
||||||
// 'Websocket handler failed with Processor actor'
|
// 'Websocket handler failed with Processor actor'
|
||||||
Source
|
Source
|
||||||
.queue[WsNotification[_]](maxBufferSize, OverflowStrategy.dropHead)
|
.queue[WsNotification[_]](maxBufferSize, OverflowStrategy.dropHead)
|
||||||
@ -667,7 +706,7 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
|
|||||||
.run()
|
.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
//need to drain the websocket queue if no one is connected
|
// need to drain the websocket queue if no one is connected
|
||||||
val _: Future[Done] = tuple._2.runWith(Sink.ignore)
|
val _: Future[Done] = tuple._2.runWith(Sink.ignore)
|
||||||
|
|
||||||
tuple
|
tuple
|
||||||
@ -703,7 +742,8 @@ object BitcoinSServerMain extends BitcoinSAppScalaDaemon {
|
|||||||
implicit lazy val conf: BitcoinSAppConfig =
|
implicit lazy val conf: BitcoinSAppConfig =
|
||||||
BitcoinSAppConfig(
|
BitcoinSAppConfig(
|
||||||
datadirParser.datadir,
|
datadirParser.datadir,
|
||||||
Vector(datadirParser.baseConfig, serverCmdLineArgs.toConfig))(system)
|
Vector(datadirParser.baseConfig, serverCmdLineArgs.toConfig)
|
||||||
|
)(system)
|
||||||
|
|
||||||
val m = new BitcoinSServerMain(serverCmdLineArgs)
|
val m = new BitcoinSServerMain(serverCmdLineArgs)
|
||||||
|
|
||||||
@ -711,7 +751,8 @@ object BitcoinSServerMain extends BitcoinSAppScalaDaemon {
|
|||||||
|
|
||||||
sys.addShutdownHook {
|
sys.addShutdownHook {
|
||||||
logger.info(
|
logger.info(
|
||||||
s"@@@@@@@@@@@@@@@@@@@@@ Shutting down ${getClass.getSimpleName} @@@@@@@@@@@@@@@@@@@@@")
|
s"@@@@@@@@@@@@@@@@@@@@@ Shutting down ${getClass.getSimpleName} @@@@@@@@@@@@@@@@@@@@@"
|
||||||
|
)
|
||||||
Await.result(m.stop(), 10.seconds)
|
Await.result(m.stop(), 10.seconds)
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
@ -32,15 +32,19 @@ import java.util.concurrent.atomic.{AtomicBoolean, AtomicInteger}
|
|||||||
import scala.concurrent.duration.{DurationInt, FiniteDuration}
|
import scala.concurrent.duration.{DurationInt, FiniteDuration}
|
||||||
import scala.concurrent.{ExecutionContext, Future, Promise}
|
import scala.concurrent.{ExecutionContext, Future, Promise}
|
||||||
|
|
||||||
/** Useful utilities to use in the wallet project for syncing things against bitcoind */
|
/** Useful utilities to use in the wallet project for syncing things against
|
||||||
|
* bitcoind
|
||||||
|
*/
|
||||||
object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
||||||
|
|
||||||
/** Has the wallet process all the blocks it has not seen up until bitcoind's chain tip */
|
/** Has the wallet process all the blocks it has not seen up until bitcoind's
|
||||||
|
* chain tip
|
||||||
|
*/
|
||||||
def syncWalletToBitcoind(
|
def syncWalletToBitcoind(
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
wallet: NeutrinoHDWalletApi,
|
wallet: NeutrinoHDWalletApi,
|
||||||
chainCallbacksOpt: Option[ChainCallbacks])(implicit
|
chainCallbacksOpt: Option[ChainCallbacks]
|
||||||
system: ActorSystem): Future[Unit] = {
|
)(implicit system: ActorSystem): Future[Unit] = {
|
||||||
logger.info("Syncing wallet to bitcoind")
|
logger.info("Syncing wallet to bitcoind")
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
|
|
||||||
@ -59,24 +63,26 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = logger.info(
|
_ = logger.info(
|
||||||
s"Syncing from bitcoind with bitcoindHeight=$bitcoindHeight walletHeight=${heightRange.start}")
|
s"Syncing from bitcoind with bitcoindHeight=$bitcoindHeight walletHeight=${heightRange.start}"
|
||||||
|
)
|
||||||
syncFlow <- buildBitcoindSyncSink(bitcoind, wallet)
|
syncFlow <- buildBitcoindSyncSink(bitcoind, wallet)
|
||||||
stream = Source(heightRange).toMat(syncFlow)(Keep.right)
|
stream = Source(heightRange).toMat(syncFlow)(Keep.right)
|
||||||
} yield stream
|
} yield stream
|
||||||
|
|
||||||
//run the stream
|
// run the stream
|
||||||
val res = streamF.flatMap(_.run())
|
val res = streamF.flatMap(_.run())
|
||||||
res.onComplete { case _ =>
|
res.onComplete { case _ =>
|
||||||
val isBitcoindInSyncF = BitcoindRpcBackendUtil.isBitcoindInSync(bitcoind)
|
val isBitcoindInSyncF = BitcoindRpcBackendUtil.isBitcoindInSync(bitcoind)
|
||||||
isBitcoindInSyncF.flatMap { isBitcoindInSync =>
|
isBitcoindInSyncF.flatMap { isBitcoindInSync =>
|
||||||
if (isBitcoindInSync) {
|
if (isBitcoindInSync) {
|
||||||
//if bitcoind is in sync, and we are in sync with bitcoind, set the syncing flag to false
|
// if bitcoind is in sync, and we are in sync with bitcoind, set the syncing flag to false
|
||||||
setSyncingFlag(false, bitcoind, chainCallbacksOpt)
|
setSyncingFlag(false, bitcoind, chainCallbacksOpt)
|
||||||
} else {
|
} else {
|
||||||
//if bitcoind is not in sync, we cannot be done syncing. Keep the syncing flag to true
|
// if bitcoind is not in sync, we cannot be done syncing. Keep the syncing flag to true
|
||||||
//so do nothing in this case
|
// so do nothing in this case
|
||||||
logger.warn(
|
logger.warn(
|
||||||
s"We synced against bitcoind, but bitcoind is not in sync with the network.")
|
s"We synced against bitcoind, but bitcoind is not in sync with the network."
|
||||||
|
)
|
||||||
Future.unit
|
Future.unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,14 +91,15 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
res.map(_ => ())
|
res.map(_ => ())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the height range for syncing against bitcoind when we don't have a [[org.bitcoins.core.api.wallet.WalletStateDescriptor]]
|
/** Gets the height range for syncing against bitcoind when we don't have a
|
||||||
* to read the sync height from.
|
* [[org.bitcoins.core.api.wallet.WalletStateDescriptor]] to read the sync
|
||||||
|
* height from.
|
||||||
*/
|
*/
|
||||||
private def getHeightRangeNoWalletState(
|
private def getHeightRangeNoWalletState(
|
||||||
wallet: NeutrinoHDWalletApi,
|
wallet: NeutrinoHDWalletApi,
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
bitcoindHeight: Int)(implicit
|
bitcoindHeight: Int
|
||||||
ex: ExecutionContext): Future[Range.Inclusive] = {
|
)(implicit ex: ExecutionContext): Future[Range.Inclusive] = {
|
||||||
for {
|
for {
|
||||||
txDbs <- wallet.listTransactions()
|
txDbs <- wallet.listTransactions()
|
||||||
lastConfirmedOpt = txDbs
|
lastConfirmedOpt = txDbs
|
||||||
@ -108,7 +115,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
range <- heightOpt match {
|
range <- heightOpt match {
|
||||||
case Some(height) =>
|
case Some(height) =>
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Last tx occurred at block $height, syncing from there")
|
s"Last tx occurred at block $height, syncing from there"
|
||||||
|
)
|
||||||
val range = height.to(bitcoindHeight)
|
val range = height.to(bitcoindHeight)
|
||||||
Future.successful(range)
|
Future.successful(range)
|
||||||
case None =>
|
case None =>
|
||||||
@ -123,8 +131,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
private def setSyncingFlag(
|
private def setSyncingFlag(
|
||||||
syncing: Boolean,
|
syncing: Boolean,
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
chainCallbacksOpt: Option[ChainCallbacks])(implicit
|
chainCallbacksOpt: Option[ChainCallbacks]
|
||||||
ec: ExecutionContext): Future[Unit] = {
|
)(implicit ec: ExecutionContext): Future[Unit] = {
|
||||||
val oldSyncingFlagF = bitcoind.isSyncing()
|
val oldSyncingFlagF = bitcoind.isSyncing()
|
||||||
for {
|
for {
|
||||||
oldFlag <- oldSyncingFlagF
|
oldFlag <- oldSyncingFlagF
|
||||||
@ -146,14 +154,16 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper method to sync the wallet until the bitcoind height.
|
/** Helper method to sync the wallet until the bitcoind height. This method
|
||||||
* This method returns a Sink that you can give block heights too and
|
* returns a Sink that you can give block heights too and the sink will
|
||||||
* the sink will synchronize our bitcoin-s wallet against bitcoind
|
* synchronize our bitcoin-s wallet against bitcoind
|
||||||
*/
|
*/
|
||||||
private def buildBitcoindSyncSink(
|
private def buildBitcoindSyncSink(
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
wallet: NeutrinoHDWalletApi)(implicit
|
wallet: NeutrinoHDWalletApi
|
||||||
system: ActorSystem): Future[Sink[Int, Future[NeutrinoHDWalletApi]]] = {
|
)(implicit
|
||||||
|
system: ActorSystem
|
||||||
|
): Future[Sink[Int, Future[NeutrinoHDWalletApi]]] = {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
|
|
||||||
val hasFiltersF = bitcoind
|
val hasFiltersF = bitcoind
|
||||||
@ -163,10 +173,10 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
.recover { case _: Throwable => false }
|
.recover { case _: Throwable => false }
|
||||||
|
|
||||||
val numParallelism = FutureUtil.getParallelism
|
val numParallelism = FutureUtil.getParallelism
|
||||||
//feeding blockchain hashes into this sync
|
// feeding blockchain hashes into this sync
|
||||||
//will sync our wallet with those blockchain hashes
|
// will sync our wallet with those blockchain hashes
|
||||||
val syncWalletSinkF: Future[
|
val syncWalletSinkF
|
||||||
Sink[DoubleSha256DigestBE, Future[NeutrinoHDWalletApi]]] = {
|
: Future[Sink[DoubleSha256DigestBE, Future[NeutrinoHDWalletApi]]] = {
|
||||||
|
|
||||||
for {
|
for {
|
||||||
hasFilters <- hasFiltersF
|
hasFilters <- hasFiltersF
|
||||||
@ -197,8 +207,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
def createWalletWithBitcoindCallbacks(
|
def createWalletWithBitcoindCallbacks(
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
wallet: Wallet,
|
wallet: Wallet,
|
||||||
chainCallbacksOpt: Option[ChainCallbacks])(implicit
|
chainCallbacksOpt: Option[ChainCallbacks]
|
||||||
system: ActorSystem): Wallet = {
|
)(implicit system: ActorSystem): Wallet = {
|
||||||
// We need to create a promise so we can inject the wallet with the callback
|
// We need to create a promise so we can inject the wallet with the callback
|
||||||
// after we have created it into SyncUtil.getNodeApiWalletCallback
|
// after we have created it into SyncUtil.getNodeApiWalletCallback
|
||||||
// so we don't lose the internal state of the wallet
|
// so we don't lose the internal state of the wallet
|
||||||
@ -207,7 +217,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
val nodeApi = BitcoindRpcBackendUtil.buildBitcoindNodeApi(
|
val nodeApi = BitcoindRpcBackendUtil.buildBitcoindNodeApi(
|
||||||
bitcoind,
|
bitcoind,
|
||||||
walletCallbackP.future,
|
walletCallbackP.future,
|
||||||
chainCallbacksOpt)
|
chainCallbacksOpt
|
||||||
|
)
|
||||||
val pairedWallet = Wallet(
|
val pairedWallet = Wallet(
|
||||||
nodeApi = nodeApi,
|
nodeApi = nodeApi,
|
||||||
chainQueryApi = bitcoind,
|
chainQueryApi = bitcoind,
|
||||||
@ -221,10 +232,12 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
|
|
||||||
def startZMQWalletCallbacks(
|
def startZMQWalletCallbacks(
|
||||||
wallet: NeutrinoHDWalletApi,
|
wallet: NeutrinoHDWalletApi,
|
||||||
zmqConfig: ZmqConfig)(implicit
|
zmqConfig: ZmqConfig
|
||||||
ec: ExecutionContext): WalletZmqSubscribers = {
|
)(implicit ec: ExecutionContext): WalletZmqSubscribers = {
|
||||||
require(zmqConfig != ZmqConfig.empty,
|
require(
|
||||||
"Must have the zmq raw configs defined to setup ZMQ callbacks")
|
zmqConfig != ZmqConfig.empty,
|
||||||
|
"Must have the zmq raw configs defined to setup ZMQ callbacks"
|
||||||
|
)
|
||||||
|
|
||||||
val rawTxSub = zmqConfig.rawTx.map { zmq =>
|
val rawTxSub = zmqConfig.rawTx.map { zmq =>
|
||||||
val rawTxListener: Option[Transaction => Unit] = Some {
|
val rawTxListener: Option[Transaction => Unit] = Some {
|
||||||
@ -238,18 +251,21 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new ZMQSubscriber(socket = zmq,
|
new ZMQSubscriber(
|
||||||
hashTxListener = None,
|
socket = zmq,
|
||||||
hashBlockListener = None,
|
hashTxListener = None,
|
||||||
rawTxListener = rawTxListener,
|
hashBlockListener = None,
|
||||||
rawBlockListener = None)
|
rawTxListener = rawTxListener,
|
||||||
|
rawBlockListener = None
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val rawBlockSub = zmqConfig.rawBlock.map { zmq =>
|
val rawBlockSub = zmqConfig.rawBlock.map { zmq =>
|
||||||
val rawBlockListener: Option[Block => Unit] = Some {
|
val rawBlockListener: Option[Block => Unit] = Some {
|
||||||
{ block: Block =>
|
{ block: Block =>
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Received block ${block.blockHeader.hashBE.hex}, processing")
|
s"Received block ${block.blockHeader.hashBE.hex}, processing"
|
||||||
|
)
|
||||||
val f = wallet.processBlock(block)
|
val f = wallet.processBlock(block)
|
||||||
f.failed.foreach { err =>
|
f.failed.foreach { err =>
|
||||||
logger.error("failed to process raw block zmq message", err)
|
logger.error("failed to process raw block zmq message", err)
|
||||||
@ -258,11 +274,13 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new ZMQSubscriber(socket = zmq,
|
new ZMQSubscriber(
|
||||||
hashTxListener = None,
|
socket = zmq,
|
||||||
hashBlockListener = None,
|
hashTxListener = None,
|
||||||
rawTxListener = None,
|
hashBlockListener = None,
|
||||||
rawBlockListener = rawBlockListener)
|
rawTxListener = None,
|
||||||
|
rawBlockListener = rawBlockListener
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val subs = WalletZmqSubscribers(rawTxSub, rawBlockSub)
|
val subs = WalletZmqSubscribers(rawTxSub, rawBlockSub)
|
||||||
@ -273,18 +291,19 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
def createDLCWalletWithBitcoindCallbacks(
|
def createDLCWalletWithBitcoindCallbacks(
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
wallet: DLCWallet,
|
wallet: DLCWallet,
|
||||||
chainCallbacksOpt: Option[ChainCallbacks])(implicit
|
chainCallbacksOpt: Option[ChainCallbacks]
|
||||||
system: ActorSystem): DLCWallet = {
|
)(implicit system: ActorSystem): DLCWallet = {
|
||||||
// We need to create a promise so we can inject the wallet with the callback
|
// We need to create a promise so we can inject the wallet with the callback
|
||||||
// after we have created it into SyncUtil.getNodeApiWalletCallback
|
// after we have created it into SyncUtil.getNodeApiWalletCallback
|
||||||
// so we don't lose the internal state of the wallet
|
// so we don't lose the internal state of the wallet
|
||||||
val walletCallbackP = Promise[DLCWallet]()
|
val walletCallbackP = Promise[DLCWallet]()
|
||||||
|
|
||||||
val pairedWallet = DLCWallet(
|
val pairedWallet = DLCWallet(
|
||||||
nodeApi =
|
nodeApi = BitcoindRpcBackendUtil.buildBitcoindNodeApi(
|
||||||
BitcoindRpcBackendUtil.buildBitcoindNodeApi(bitcoind,
|
bitcoind,
|
||||||
walletCallbackP.future,
|
walletCallbackP.future,
|
||||||
chainCallbacksOpt),
|
chainCallbacksOpt
|
||||||
|
),
|
||||||
chainQueryApi = bitcoind,
|
chainQueryApi = bitcoind,
|
||||||
feeRateApi = wallet.feeRateApi
|
feeRateApi = wallet.feeRateApi
|
||||||
)(wallet.walletConfig, wallet.dlcConfig)
|
)(wallet.walletConfig, wallet.dlcConfig)
|
||||||
@ -296,9 +315,10 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
|
|
||||||
private def filterSyncSink(
|
private def filterSyncSink(
|
||||||
bitcoindRpcClient: BlockchainRpc,
|
bitcoindRpcClient: BlockchainRpc,
|
||||||
wallet: NeutrinoHDWalletApi)(implicit ec: ExecutionContext): Sink[
|
wallet: NeutrinoHDWalletApi
|
||||||
DoubleSha256DigestBE,
|
)(implicit
|
||||||
Future[NeutrinoHDWalletApi]] = {
|
ec: ExecutionContext
|
||||||
|
): Sink[DoubleSha256DigestBE, Future[NeutrinoHDWalletApi]] = {
|
||||||
|
|
||||||
val numParallelism = FutureUtil.getParallelism
|
val numParallelism = FutureUtil.getParallelism
|
||||||
val sink: Sink[DoubleSha256DigestBE, Future[NeutrinoHDWalletApi]] =
|
val sink: Sink[DoubleSha256DigestBE, Future[NeutrinoHDWalletApi]] =
|
||||||
@ -317,39 +337,46 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
sink
|
sink
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates an anonymous [[NodeApi]] that downloads blocks using
|
/** Creates an anonymous [[NodeApi]] that downloads blocks using akka streams
|
||||||
* akka streams from bitcoind, and then calls [[NeutrinoWalletApi.processBlock]]
|
* from bitcoind, and then calls [[NeutrinoWalletApi.processBlock]]
|
||||||
*/
|
*/
|
||||||
def buildBitcoindNodeApi(
|
def buildBitcoindNodeApi(
|
||||||
bitcoindRpcClient: BitcoindRpcClient,
|
bitcoindRpcClient: BitcoindRpcClient,
|
||||||
walletF: Future[WalletApi],
|
walletF: Future[WalletApi],
|
||||||
chainCallbacksOpt: Option[ChainCallbacks])(implicit
|
chainCallbacksOpt: Option[ChainCallbacks]
|
||||||
system: ActorSystem): NodeApi = {
|
)(implicit system: ActorSystem): NodeApi = {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
new NodeApi {
|
new NodeApi {
|
||||||
|
|
||||||
override def downloadBlocks(
|
override def downloadBlocks(
|
||||||
blockHashes: Vector[DoubleSha256DigestBE]): Future[Unit] = {
|
blockHashes: Vector[DoubleSha256DigestBE]
|
||||||
|
): Future[Unit] = {
|
||||||
logger.info(s"Fetching ${blockHashes.length} blocks from bitcoind")
|
logger.info(s"Fetching ${blockHashes.length} blocks from bitcoind")
|
||||||
val numParallelism = FutureUtil.getParallelism
|
val numParallelism = FutureUtil.getParallelism
|
||||||
val source = Source(blockHashes)
|
val source = Source(blockHashes)
|
||||||
val fetchBlocksFlow = BitcoindStreamUtil.fetchBlocksBitcoind(
|
val fetchBlocksFlow = BitcoindStreamUtil.fetchBlocksBitcoind(
|
||||||
bitcoindRpcClient = bitcoindRpcClient,
|
bitcoindRpcClient = bitcoindRpcClient,
|
||||||
parallelism = numParallelism)
|
parallelism = numParallelism
|
||||||
|
)
|
||||||
|
|
||||||
val sinkF: Future[
|
val sinkF
|
||||||
Sink[(Block, GetBlockHeaderResult), Future[WalletApi]]] = {
|
: Future[Sink[(Block, GetBlockHeaderResult), Future[WalletApi]]] = {
|
||||||
walletF.map { initWallet =>
|
walletF.map { initWallet =>
|
||||||
Sink.foldAsync[WalletApi, (Block, GetBlockHeaderResult)](
|
Sink.foldAsync[WalletApi, (Block, GetBlockHeaderResult)](
|
||||||
initWallet) {
|
initWallet
|
||||||
case (wallet: WalletApi,
|
) {
|
||||||
(block: Block, blockHeaderResult: GetBlockHeaderResult)) =>
|
case (
|
||||||
|
wallet: WalletApi,
|
||||||
|
(block: Block, blockHeaderResult: GetBlockHeaderResult)
|
||||||
|
) =>
|
||||||
val blockProcessedF = wallet.processBlock(block)
|
val blockProcessedF = wallet.processBlock(block)
|
||||||
val executeCallbackF: Future[WalletApi] = {
|
val executeCallbackF: Future[WalletApi] = {
|
||||||
for {
|
for {
|
||||||
wallet <- blockProcessedF
|
wallet <- blockProcessedF
|
||||||
_ <- handleChainCallbacks(chainCallbacksOpt,
|
_ <- handleChainCallbacks(
|
||||||
blockHeaderResult)
|
chainCallbacksOpt,
|
||||||
|
blockHeaderResult
|
||||||
|
)
|
||||||
} yield wallet
|
} yield wallet
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,7 +401,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
/** Broadcasts the given transaction over the P2P network
|
/** Broadcasts the given transaction over the P2P network
|
||||||
*/
|
*/
|
||||||
override def broadcastTransactions(
|
override def broadcastTransactions(
|
||||||
transactions: Vector[Transaction]): Future[Unit] = {
|
transactions: Vector[Transaction]
|
||||||
|
): Future[Unit] = {
|
||||||
bitcoindRpcClient.broadcastTransactions(transactions)
|
bitcoindRpcClient.broadcastTransactions(transactions)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,12 +414,12 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
|
|
||||||
private def handleChainCallbacks(
|
private def handleChainCallbacks(
|
||||||
chainCallbacksOpt: Option[ChainCallbacks],
|
chainCallbacksOpt: Option[ChainCallbacks],
|
||||||
blockHeaderResult: GetBlockHeaderResult)(implicit
|
blockHeaderResult: GetBlockHeaderResult
|
||||||
ec: ExecutionContext): Future[Unit] = {
|
)(implicit ec: ExecutionContext): Future[Unit] = {
|
||||||
chainCallbacksOpt match {
|
chainCallbacksOpt match {
|
||||||
case None => Future.unit
|
case None => Future.unit
|
||||||
case Some(callback) =>
|
case Some(callback) =>
|
||||||
//this can be slow as we aren't batching headers at all
|
// this can be slow as we aren't batching headers at all
|
||||||
val headerWithHeights =
|
val headerWithHeights =
|
||||||
Vector((blockHeaderResult.height, blockHeaderResult.blockHeader))
|
Vector((blockHeaderResult.height, blockHeaderResult.blockHeader))
|
||||||
val f = callback
|
val f = callback
|
||||||
@ -400,19 +428,22 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Starts the [[ActorSystem]] to poll the [[BitcoindRpcClient]] for its block count,
|
/** Starts the [[ActorSystem]] to poll the [[BitcoindRpcClient]] for its block
|
||||||
* if it has changed, it will then request those blocks to process them
|
* count, if it has changed, it will then request those blocks to process
|
||||||
|
* them
|
||||||
*
|
*
|
||||||
* @param startCount The starting block height of the wallet
|
* @param startCount
|
||||||
* @param interval The amount of time between polls, this should not be too aggressive
|
* The starting block height of the wallet
|
||||||
* as the wallet will need to process the new blocks
|
* @param interval
|
||||||
|
* The amount of time between polls, this should not be too aggressive as
|
||||||
|
* the wallet will need to process the new blocks
|
||||||
*/
|
*/
|
||||||
def startBitcoindBlockPolling(
|
def startBitcoindBlockPolling(
|
||||||
wallet: WalletApi,
|
wallet: WalletApi,
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
chainCallbacksOpt: Option[ChainCallbacks],
|
chainCallbacksOpt: Option[ChainCallbacks],
|
||||||
interval: FiniteDuration = 10.seconds)(implicit
|
interval: FiniteDuration = 10.seconds
|
||||||
system: ActorSystem): Cancellable = {
|
)(implicit system: ActorSystem): Cancellable = {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
|
|
||||||
val processingBitcoindBlocks = new AtomicBoolean(false)
|
val processingBitcoindBlocks = new AtomicBoolean(false)
|
||||||
@ -431,10 +462,12 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
res <-
|
res <-
|
||||||
if (!rescanning) {
|
if (!rescanning) {
|
||||||
val pollFOptF =
|
val pollFOptF =
|
||||||
pollBitcoind(wallet = wallet,
|
pollBitcoind(
|
||||||
bitcoind = bitcoind,
|
wallet = wallet,
|
||||||
chainCallbacksOpt = chainCallbacksOpt,
|
bitcoind = bitcoind,
|
||||||
prevCount = walletSyncState.height)
|
chainCallbacksOpt = chainCallbacksOpt,
|
||||||
|
prevCount = walletSyncState.height
|
||||||
|
)
|
||||||
|
|
||||||
pollFOptF.flatMap {
|
pollFOptF.flatMap {
|
||||||
case Some(pollF) => pollF
|
case Some(pollF) => pollF
|
||||||
@ -442,17 +475,20 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Skipping scanning the blockchain during wallet rescan")
|
s"Skipping scanning the blockchain during wallet rescan"
|
||||||
|
)
|
||||||
Future.unit
|
Future.unit
|
||||||
}
|
}
|
||||||
} yield res
|
} yield res
|
||||||
|
|
||||||
f.onComplete { _ =>
|
f.onComplete { _ =>
|
||||||
processingBitcoindBlocks.set(false)
|
processingBitcoindBlocks.set(false)
|
||||||
BitcoindRpcBackendUtil.setSyncingFlag(false,
|
BitcoindRpcBackendUtil.setSyncingFlag(
|
||||||
bitcoind,
|
false,
|
||||||
chainCallbacksOpt)
|
bitcoind,
|
||||||
} //reset polling variable
|
chainCallbacksOpt
|
||||||
|
)
|
||||||
|
} // reset polling variable
|
||||||
f.failed.foreach(err =>
|
f.failed.foreach(err =>
|
||||||
logger.error(s"Failed to poll bitcoind", err))
|
logger.error(s"Failed to poll bitcoind", err))
|
||||||
} else {
|
} else {
|
||||||
@ -465,14 +501,16 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Polls bitcoind for syncing the blockchain
|
/** Polls bitcoind for syncing the blockchain
|
||||||
* @return None if there was nothing to sync, else the Future[Done] that is completed when the sync is finished.
|
* @return
|
||||||
|
* None if there was nothing to sync, else the Future[Done] that is
|
||||||
|
* completed when the sync is finished.
|
||||||
*/
|
*/
|
||||||
private def pollBitcoind(
|
private def pollBitcoind(
|
||||||
wallet: WalletApi,
|
wallet: WalletApi,
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
chainCallbacksOpt: Option[ChainCallbacks],
|
chainCallbacksOpt: Option[ChainCallbacks],
|
||||||
prevCount: Int)(implicit
|
prevCount: Int
|
||||||
system: ActorSystem): Future[Option[Future[Done]]] = {
|
)(implicit system: ActorSystem): Future[Option[Future[Done]]] = {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
val atomicPrevCount = new AtomicInteger(prevCount)
|
val atomicPrevCount = new AtomicInteger(prevCount)
|
||||||
val queueSource: Source[Int, SourceQueueWithComplete[Int]] =
|
val queueSource: Source[Int, SourceQueueWithComplete[Int]] =
|
||||||
@ -492,7 +530,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
atomicPrevCount.set(prevCount)
|
atomicPrevCount.set(prevCount)
|
||||||
logger.error(
|
logger.error(
|
||||||
s"Processing blocks from bitcoind polling failed, range=[$prevCount, $failedCount]",
|
s"Processing blocks from bitcoind polling failed, range=[$prevCount, $failedCount]",
|
||||||
err)
|
err
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -523,7 +562,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
retval <- {
|
retval <- {
|
||||||
if (prevCount < count) {
|
if (prevCount < count) {
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Bitcoind has new block(s), requesting... ${count - prevCount} blocks")
|
s"Bitcoind has new block(s), requesting... ${count - prevCount} blocks"
|
||||||
|
)
|
||||||
val setSyncFlagF = setSyncingFlag(true, bitcoind, chainCallbacksOpt)
|
val setSyncFlagF = setSyncingFlag(true, bitcoind, chainCallbacksOpt)
|
||||||
setSyncFlagF.map { _ =>
|
setSyncFlagF.map { _ =>
|
||||||
// use .tail so we don't process the previous block that we already did
|
// use .tail so we don't process the previous block that we already did
|
||||||
@ -531,15 +571,18 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
range.foreach(r => queue.offer(r))
|
range.foreach(r => queue.offer(r))
|
||||||
}
|
}
|
||||||
} else if (prevCount > count) {
|
} else if (prevCount > count) {
|
||||||
Future.failed(new RuntimeException(
|
Future.failed(
|
||||||
s"Bitcoind is at a block height ($count) before the wallet's ($prevCount)"))
|
new RuntimeException(
|
||||||
|
s"Bitcoind is at a block height ($count) before the wallet's ($prevCount)"
|
||||||
|
)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
logger.debug(s"In sync $prevCount count=$count")
|
logger.debug(s"In sync $prevCount count=$count")
|
||||||
Future.unit
|
Future.unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} yield {
|
} yield {
|
||||||
queue.complete() //complete the stream after offering all heights we need to sync
|
queue.complete() // complete the stream after offering all heights we need to sync
|
||||||
retval
|
retval
|
||||||
}
|
}
|
||||||
resF.map(_ => Some(doneF))
|
resF.map(_ => Some(doneF))
|
||||||
@ -548,15 +591,16 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
def startBitcoindMempoolPolling(
|
def startBitcoindMempoolPolling(
|
||||||
wallet: WalletApi,
|
wallet: WalletApi,
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
interval: FiniteDuration = 10.seconds)(
|
interval: FiniteDuration = 10.seconds
|
||||||
processTx: Transaction => Future[Unit])(implicit
|
)(
|
||||||
system: ActorSystem,
|
processTx: Transaction => Future[Unit]
|
||||||
ec: ExecutionContext): Cancellable = {
|
)(implicit system: ActorSystem, ec: ExecutionContext): Cancellable = {
|
||||||
@volatile var prevMempool: Set[DoubleSha256DigestBE] =
|
@volatile var prevMempool: Set[DoubleSha256DigestBE] =
|
||||||
Set.empty[DoubleSha256DigestBE]
|
Set.empty[DoubleSha256DigestBE]
|
||||||
|
|
||||||
def getDiffAndReplace(
|
def getDiffAndReplace(
|
||||||
newMempool: Set[DoubleSha256DigestBE]): Set[DoubleSha256DigestBE] =
|
newMempool: Set[DoubleSha256DigestBE]
|
||||||
|
): Set[DoubleSha256DigestBE] =
|
||||||
synchronized {
|
synchronized {
|
||||||
val txids = newMempool.diff(prevMempool)
|
val txids = newMempool.diff(prevMempool)
|
||||||
prevMempool = newMempool
|
prevMempool = newMempool
|
||||||
@ -570,7 +614,7 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
logger.debug("Polling bitcoind for mempool")
|
logger.debug("Polling bitcoind for mempool")
|
||||||
val numParallelism = FutureUtil.getParallelism
|
val numParallelism = FutureUtil.getParallelism
|
||||||
|
|
||||||
//don't want to execute these in parallel
|
// don't want to execute these in parallel
|
||||||
val processTxFlow = Sink.foreachAsync[Option[Transaction]](1) {
|
val processTxFlow = Sink.foreachAsync[Option[Transaction]](1) {
|
||||||
case Some(tx) => processTx(tx)
|
case Some(tx) => processTx(tx)
|
||||||
case None => Future.unit
|
case None => Future.unit
|
||||||
@ -594,14 +638,16 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
.run()
|
.run()
|
||||||
} yield {
|
} yield {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
s"Done processing ${newTxIds.size} new mempool transactions")
|
s"Done processing ${newTxIds.size} new mempool transactions"
|
||||||
|
)
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
res.onComplete(_ => processingMempool.set(false))
|
res.onComplete(_ => processingMempool.set(false))
|
||||||
res
|
res
|
||||||
} else {
|
} else {
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Skipping scanning the mempool since a previously scheduled task is still running")
|
s"Skipping scanning the mempool since a previously scheduled task is still running"
|
||||||
|
)
|
||||||
Future.unit
|
Future.unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -625,9 +671,12 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Checks if bitcoind has all blocks for the headers it has seen on the network */
|
/** Checks if bitcoind has all blocks for the headers it has seen on the
|
||||||
private def isBitcoindInSync(bitcoind: BitcoindRpcClient)(implicit
|
* network
|
||||||
ec: ExecutionContext): Future[Boolean] = {
|
*/
|
||||||
|
private def isBitcoindInSync(
|
||||||
|
bitcoind: BitcoindRpcClient
|
||||||
|
)(implicit ec: ExecutionContext): Future[Boolean] = {
|
||||||
for {
|
for {
|
||||||
blockchainInfo <- bitcoind.getBlockChainInfo
|
blockchainInfo <- bitcoind.getBlockChainInfo
|
||||||
} yield {
|
} yield {
|
||||||
|
@ -17,7 +17,8 @@ import scala.concurrent.Future
|
|||||||
case class ChainRoutes(
|
case class ChainRoutes(
|
||||||
chain: ChainApi,
|
chain: ChainApi,
|
||||||
network: BitcoinNetwork,
|
network: BitcoinNetwork,
|
||||||
startedTorConfigF: Future[Unit])(implicit system: ActorSystem)
|
startedTorConfigF: Future[Unit]
|
||||||
|
)(implicit system: ActorSystem)
|
||||||
extends ServerRoute {
|
extends ServerRoute {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
|
|
||||||
@ -59,8 +60,8 @@ case class ChainRoutes(
|
|||||||
for {
|
for {
|
||||||
results <- resultsF
|
results <- resultsF
|
||||||
} yield {
|
} yield {
|
||||||
val json = upickle.default.writeJs(results.head)(
|
val json = upickle.default
|
||||||
Picklers.getBlockHeaderResultPickler)
|
.writeJs(results.head)(Picklers.getBlockHeaderResultPickler)
|
||||||
Server.httpSuccess(json)
|
Server.httpSuccess(json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,8 @@ case class CoreRoutes()(implicit system: ActorSystem, config: BitcoinSAppConfig)
|
|||||||
case DecodeContractInfo(contractInfo) =>
|
case DecodeContractInfo(contractInfo) =>
|
||||||
complete {
|
complete {
|
||||||
Server.httpSuccess(
|
Server.httpSuccess(
|
||||||
writeJs(contractInfo)(contractInfoV0TLVJsonWriter))
|
writeJs(contractInfo)(contractInfoV0TLVJsonWriter)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +182,8 @@ case class CoreRoutes()(implicit system: ActorSystem, config: BitcoinSAppConfig)
|
|||||||
case DecodeAnnouncement(announcement) =>
|
case DecodeAnnouncement(announcement) =>
|
||||||
complete {
|
complete {
|
||||||
Server.httpSuccess(
|
Server.httpSuccess(
|
||||||
writeJs(announcement)(oracleAnnouncementTLVJsonWriter))
|
writeJs(announcement)(oracleAnnouncementTLVJsonWriter)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,10 +42,12 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
|
|||||||
case AcceptDLC(offer, address, payoutAddressOpt, changeAddressOpt) =>
|
case AcceptDLC(offer, address, payoutAddressOpt, changeAddressOpt) =>
|
||||||
complete {
|
complete {
|
||||||
dlcNode
|
dlcNode
|
||||||
.acceptDLCOffer(address,
|
.acceptDLCOffer(
|
||||||
offer,
|
address,
|
||||||
payoutAddressOpt,
|
offer,
|
||||||
changeAddressOpt)
|
payoutAddressOpt,
|
||||||
|
changeAddressOpt
|
||||||
|
)
|
||||||
.map { accept =>
|
.map { accept =>
|
||||||
Server.httpSuccess(accept.toMessage.hex)
|
Server.httpSuccess(accept.toMessage.hex)
|
||||||
}
|
}
|
||||||
@ -63,9 +65,11 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
|
|||||||
case _: EnumEventDescriptorV0TLV =>
|
case _: EnumEventDescriptorV0TLV =>
|
||||||
EnumSingleOracleInfo(create.announcementTLV)
|
EnumSingleOracleInfo(create.announcementTLV)
|
||||||
}
|
}
|
||||||
val contractInfo = SingleContractInfo(create.totalCollateral,
|
val contractInfo = SingleContractInfo(
|
||||||
create.ContractDescriptorTLV,
|
create.totalCollateral,
|
||||||
oracleInfo)
|
create.ContractDescriptorTLV,
|
||||||
|
oracleInfo
|
||||||
|
)
|
||||||
Server.httpSuccess(contractInfo.hex)
|
Server.httpSuccess(contractInfo.hex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,9 +95,11 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
|
|||||||
withValidServerCommand(OfferAdd.fromJsArr(arr)) { register =>
|
withValidServerCommand(OfferAdd.fromJsArr(arr)) { register =>
|
||||||
complete {
|
complete {
|
||||||
dlcNode.wallet
|
dlcNode.wallet
|
||||||
.registerIncomingDLCOffer(register.offerTLV,
|
.registerIncomingDLCOffer(
|
||||||
register.peer,
|
register.offerTLV,
|
||||||
register.message)
|
register.peer,
|
||||||
|
register.message
|
||||||
|
)
|
||||||
.map { hash =>
|
.map { hash =>
|
||||||
Server.httpSuccess(hash.hex)
|
Server.httpSuccess(hash.hex)
|
||||||
}
|
}
|
||||||
@ -133,8 +139,8 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
|
|||||||
case ServerCommand("contacts-list", _) =>
|
case ServerCommand("contacts-list", _) =>
|
||||||
complete {
|
complete {
|
||||||
dlcNode.wallet.listDLCContacts().map { contacts =>
|
dlcNode.wallet.listDLCContacts().map { contacts =>
|
||||||
val json = contacts.map(c =>
|
val json = contacts
|
||||||
upickle.default.writeJs(c)(Picklers.contactDbPickler))
|
.map(c => upickle.default.writeJs(c)(Picklers.contactDbPickler))
|
||||||
Server.httpSuccess(json)
|
Server.httpSuccess(json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,7 +177,8 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
|
|||||||
val contactId =
|
val contactId =
|
||||||
dlcContactAdd.address.getHostName + ":" + dlcContactAdd.address.getPort
|
dlcContactAdd.address.getHostName + ":" + dlcContactAdd.address.getPort
|
||||||
Server.httpSuccess(
|
Server.httpSuccess(
|
||||||
ujson.Obj("dlcId" -> dlcId, "contactId" -> contactId))
|
ujson.Obj("dlcId" -> dlcId, "contactId" -> contactId)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,9 @@ import org.bitcoins.wallet.config.WalletAppConfig
|
|||||||
|
|
||||||
import scala.concurrent.{ExecutionContext, Future}
|
import scala.concurrent.{ExecutionContext, Future}
|
||||||
|
|
||||||
/** A trait used to help load a different load and discard the current wallet in memory
|
/** A trait used to help load a different load and discard the current wallet in
|
||||||
* This trait encapsulates the heavy lifting done in the 'loadwallet' RPC command
|
* memory This trait encapsulates the heavy lifting done in the 'loadwallet'
|
||||||
|
* RPC command
|
||||||
*/
|
*/
|
||||||
sealed trait DLCWalletLoaderApi
|
sealed trait DLCWalletLoaderApi
|
||||||
extends BitcoinSLogger
|
extends BitcoinSLogger
|
||||||
@ -42,8 +43,8 @@ sealed trait DLCWalletLoaderApi
|
|||||||
|
|
||||||
def load(
|
def load(
|
||||||
walletNameOpt: Option[String],
|
walletNameOpt: Option[String],
|
||||||
aesPasswordOpt: Option[AesPassword]): Future[
|
aesPasswordOpt: Option[AesPassword]
|
||||||
(WalletHolder, WalletAppConfig, DLCAppConfig)]
|
): Future[(WalletHolder, WalletAppConfig, DLCAppConfig)]
|
||||||
|
|
||||||
protected def loadWallet(
|
protected def loadWallet(
|
||||||
walletHolder: WalletHolder,
|
walletHolder: WalletHolder,
|
||||||
@ -51,17 +52,21 @@ sealed trait DLCWalletLoaderApi
|
|||||||
nodeApi: NodeApi,
|
nodeApi: NodeApi,
|
||||||
feeProviderApi: FeeRateApi,
|
feeProviderApi: FeeRateApi,
|
||||||
walletNameOpt: Option[String],
|
walletNameOpt: Option[String],
|
||||||
aesPasswordOpt: Option[AesPassword])(implicit
|
aesPasswordOpt: Option[AesPassword]
|
||||||
ec: ExecutionContext): Future[
|
)(implicit
|
||||||
(DLCNeutrinoHDWalletApi, WalletAppConfig, DLCAppConfig)] = {
|
ec: ExecutionContext
|
||||||
|
): Future[(DLCNeutrinoHDWalletApi, WalletAppConfig, DLCAppConfig)] = {
|
||||||
logger.info(
|
logger.info(
|
||||||
s"Loading wallet with bitcoind backend, walletName=${walletNameOpt.getOrElse("DEFAULT")}")
|
s"Loading wallet with bitcoind backend, walletName=${walletNameOpt.getOrElse("DEFAULT")}"
|
||||||
|
)
|
||||||
val walletName =
|
val walletName =
|
||||||
walletNameOpt.getOrElse(WalletAppConfig.DEFAULT_WALLET_NAME)
|
walletNameOpt.getOrElse(WalletAppConfig.DEFAULT_WALLET_NAME)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
(walletConfig, dlcConfig) <- updateWalletConfigs(walletName,
|
(walletConfig, dlcConfig) <- updateWalletConfigs(
|
||||||
aesPasswordOpt)
|
walletName,
|
||||||
|
aesPasswordOpt
|
||||||
|
)
|
||||||
_ <- {
|
_ <- {
|
||||||
if (walletHolder.isInitialized) {
|
if (walletHolder.isInitialized) {
|
||||||
walletHolder
|
walletHolder
|
||||||
@ -83,8 +88,8 @@ sealed trait DLCWalletLoaderApi
|
|||||||
|
|
||||||
protected def updateWalletConfigs(
|
protected def updateWalletConfigs(
|
||||||
walletName: String,
|
walletName: String,
|
||||||
aesPasswordOpt: Option[AesPassword])(implicit
|
aesPasswordOpt: Option[AesPassword]
|
||||||
ec: ExecutionContext): Future[(WalletAppConfig, DLCAppConfig)] = {
|
)(implicit ec: ExecutionContext): Future[(WalletAppConfig, DLCAppConfig)] = {
|
||||||
val walletNameArgOpt = ArgumentSource.RpcArgument(walletName)
|
val walletNameArgOpt = ArgumentSource.RpcArgument(walletName)
|
||||||
val aesPasswordArgOpt = aesPasswordOpt match {
|
val aesPasswordArgOpt = aesPasswordOpt match {
|
||||||
case None =>
|
case None =>
|
||||||
@ -93,8 +98,11 @@ sealed trait DLCWalletLoaderApi
|
|||||||
Some(ArgumentSource.RpcArgument(pw))
|
Some(ArgumentSource.RpcArgument(pw))
|
||||||
}
|
}
|
||||||
val kmConfigF = Future.successful(
|
val kmConfigF = Future.successful(
|
||||||
conf.walletConf.kmConf.copy(walletNameOverride = Some(walletNameArgOpt),
|
conf.walletConf.kmConf.copy(
|
||||||
aesPasswordOverride = aesPasswordArgOpt))
|
walletNameOverride = Some(walletNameArgOpt),
|
||||||
|
aesPasswordOverride = aesPasswordArgOpt
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
(for {
|
(for {
|
||||||
kmConfig <- kmConfigF
|
kmConfig <- kmConfigF
|
||||||
@ -107,46 +115,49 @@ sealed trait DLCWalletLoaderApi
|
|||||||
} yield (walletConfig, dlcConfig))
|
} yield (walletConfig, dlcConfig))
|
||||||
}
|
}
|
||||||
|
|
||||||
protected def updateWalletName(walletNameOpt: Option[String])(implicit
|
protected def updateWalletName(
|
||||||
ec: ExecutionContext): Future[Unit] = {
|
walletNameOpt: Option[String]
|
||||||
|
)(implicit ec: ExecutionContext): Future[Unit] = {
|
||||||
val nodeStateDAO: NodeStateDescriptorDAO =
|
val nodeStateDAO: NodeStateDescriptorDAO =
|
||||||
NodeStateDescriptorDAO()(ec, conf.nodeConf)
|
NodeStateDescriptorDAO()(ec, conf.nodeConf)
|
||||||
nodeStateDAO.updateWalletName(walletNameOpt)
|
nodeStateDAO.updateWalletName(walletNameOpt)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected def restartRescanIfNeeded(wallet: DLCNeutrinoHDWalletApi)(implicit
|
protected def restartRescanIfNeeded(
|
||||||
ec: ExecutionContext): Future[RescanState] = {
|
wallet: DLCNeutrinoHDWalletApi
|
||||||
|
)(implicit ec: ExecutionContext): Future[RescanState] = {
|
||||||
for {
|
for {
|
||||||
isRescanning <- wallet.isRescanning()
|
isRescanning <- wallet.isRescanning()
|
||||||
res <-
|
res <-
|
||||||
if (isRescanning)
|
if (isRescanning)
|
||||||
wallet.rescanNeutrinoWallet(startOpt = None,
|
wallet.rescanNeutrinoWallet(
|
||||||
endOpt = None,
|
startOpt = None,
|
||||||
addressBatchSize =
|
endOpt = None,
|
||||||
wallet.discoveryBatchSize(),
|
addressBatchSize = wallet.discoveryBatchSize(),
|
||||||
useCreationTime = true,
|
useCreationTime = true,
|
||||||
force = true)
|
force = true
|
||||||
|
)
|
||||||
else Future.successful(RescanState.RescanDone)
|
else Future.successful(RescanState.RescanDone)
|
||||||
} yield res
|
} yield res
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Store a rescan state for the wallet that is currently loaded
|
/** Store a rescan state for the wallet that is currently loaded This is
|
||||||
* This is needed because we don't save rescan state anywhere else.
|
* needed because we don't save rescan state anywhere else.
|
||||||
*/
|
*/
|
||||||
@volatile private[this] var rescanStateOpt: Option[
|
@volatile private[this] var rescanStateOpt
|
||||||
RescanState.RescanStarted] = None
|
: Option[RescanState.RescanStarted] = None
|
||||||
|
|
||||||
def setRescanState(rescanState: RescanState): Unit = {
|
def setRescanState(rescanState: RescanState): Unit = {
|
||||||
rescanState match {
|
rescanState match {
|
||||||
case RescanState.RescanAlreadyStarted =>
|
case RescanState.RescanAlreadyStarted =>
|
||||||
//do nothing in this case, we don't need to keep these states around
|
// do nothing in this case, we don't need to keep these states around
|
||||||
//don't overwrite the existing reference to RescanStarted
|
// don't overwrite the existing reference to RescanStarted
|
||||||
case RescanState.RescanDone | RescanState.RescanNotNeeded =>
|
case RescanState.RescanDone | RescanState.RescanNotNeeded =>
|
||||||
//rescan is done, reset state
|
// rescan is done, reset state
|
||||||
rescanStateOpt = None
|
rescanStateOpt = None
|
||||||
case started: RescanState.RescanStarted =>
|
case started: RescanState.RescanStarted =>
|
||||||
if (rescanStateOpt.isEmpty) {
|
if (rescanStateOpt.isEmpty) {
|
||||||
//add callback to reset state when the rescan is done
|
// add callback to reset state when the rescan is done
|
||||||
val resetStateCallbackF = started.entireRescanDoneF.map { _ =>
|
val resetStateCallbackF = started.entireRescanDoneF.map { _ =>
|
||||||
rescanStateOpt = None
|
rescanStateOpt = None
|
||||||
}
|
}
|
||||||
@ -156,20 +167,22 @@ sealed trait DLCWalletLoaderApi
|
|||||||
case scala.util.control.NonFatal(exn) =>
|
case scala.util.control.NonFatal(exn) =>
|
||||||
logger.error(
|
logger.error(
|
||||||
s"Failed to reset rescanState in wallet loader. Resetting rescan state",
|
s"Failed to reset rescanState in wallet loader. Resetting rescan state",
|
||||||
exn)
|
exn
|
||||||
|
)
|
||||||
rescanStateOpt = None
|
rescanStateOpt = None
|
||||||
}
|
}
|
||||||
rescanStateOpt = Some(started)
|
rescanStateOpt = Some(started)
|
||||||
} else {
|
} else {
|
||||||
sys.error(
|
sys.error(
|
||||||
s"Cannot run multiple rescans at the same time, got=$started have=$rescanStateOpt")
|
s"Cannot run multiple rescans at the same time, got=$started have=$rescanStateOpt"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected def stopRescan()(implicit ec: ExecutionContext): Future[Unit] = {
|
protected def stopRescan()(implicit ec: ExecutionContext): Future[Unit] = {
|
||||||
rescanStateOpt match {
|
rescanStateOpt match {
|
||||||
case Some(state) => state.stop().map(_ => ()) //stop the rescan
|
case Some(state) => state.stop().map(_ => ()) // stop the rescan
|
||||||
case None => Future.unit
|
case None => Future.unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,17 +201,18 @@ sealed trait DLCWalletLoaderApi
|
|||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
||||||
@volatile private[this] var currentWalletAppConfigOpt: Option[
|
@volatile private[this] var currentWalletAppConfigOpt
|
||||||
WalletAppConfig] = None
|
: Option[WalletAppConfig] = None
|
||||||
|
|
||||||
@volatile private[this] var currentDLCAppConfigOpt: Option[DLCAppConfig] =
|
@volatile private[this] var currentDLCAppConfigOpt: Option[DLCAppConfig] =
|
||||||
None
|
None
|
||||||
|
|
||||||
protected def stopOldWalletAppConfig(
|
protected def stopOldWalletAppConfig(
|
||||||
newWalletConfig: WalletAppConfig): Future[Unit] = {
|
newWalletConfig: WalletAppConfig
|
||||||
|
): Future[Unit] = {
|
||||||
currentWalletAppConfigOpt match {
|
currentWalletAppConfigOpt match {
|
||||||
case Some(current) =>
|
case Some(current) =>
|
||||||
//stop the old config
|
// stop the old config
|
||||||
current
|
current
|
||||||
.stop()
|
.stop()
|
||||||
.map(_ => {
|
.map(_ => {
|
||||||
@ -214,10 +228,11 @@ sealed trait DLCWalletLoaderApi
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected def stopOldDLCAppConfig(
|
protected def stopOldDLCAppConfig(
|
||||||
newDlcConfig: DLCAppConfig): Future[Unit] = {
|
newDlcConfig: DLCAppConfig
|
||||||
|
): Future[Unit] = {
|
||||||
currentDLCAppConfigOpt match {
|
currentDLCAppConfigOpt match {
|
||||||
case Some(current) =>
|
case Some(current) =>
|
||||||
//stop the old config
|
// stop the old config
|
||||||
current
|
current
|
||||||
.stop()
|
.stop()
|
||||||
.map(_ => {
|
.map(_ => {
|
||||||
@ -266,10 +281,11 @@ case class DLCWalletNeutrinoBackendLoader(
|
|||||||
walletHolder: WalletHolder,
|
walletHolder: WalletHolder,
|
||||||
chainQueryApi: ChainQueryApi,
|
chainQueryApi: ChainQueryApi,
|
||||||
nodeApi: NodeApi,
|
nodeApi: NodeApi,
|
||||||
feeRateApi: FeeRateApi)(implicit
|
feeRateApi: FeeRateApi
|
||||||
|
)(implicit
|
||||||
override val conf: BitcoinSAppConfig,
|
override val conf: BitcoinSAppConfig,
|
||||||
override val system: ActorSystem)
|
override val system: ActorSystem
|
||||||
extends DLCWalletLoaderApi {
|
) extends DLCWalletLoaderApi {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
|
|
||||||
implicit private val nodeConf: NodeAppConfig = conf.nodeConf
|
implicit private val nodeConf: NodeAppConfig = conf.nodeConf
|
||||||
@ -278,8 +294,8 @@ case class DLCWalletNeutrinoBackendLoader(
|
|||||||
|
|
||||||
override def load(
|
override def load(
|
||||||
walletNameOpt: Option[String],
|
walletNameOpt: Option[String],
|
||||||
aesPasswordOpt: Option[AesPassword]): Future[
|
aesPasswordOpt: Option[AesPassword]
|
||||||
(WalletHolder, WalletAppConfig, DLCAppConfig)] = {
|
): Future[(WalletHolder, WalletAppConfig, DLCAppConfig)] = {
|
||||||
val stopCallbackF = nodeConf.callBacks match {
|
val stopCallbackF = nodeConf.callBacks match {
|
||||||
case stream: NodeCallbackStreamManager =>
|
case stream: NodeCallbackStreamManager =>
|
||||||
stream.stop()
|
stream.stop()
|
||||||
@ -320,17 +336,18 @@ case class DLCWalletBitcoindBackendLoader(
|
|||||||
walletHolder: WalletHolder,
|
walletHolder: WalletHolder,
|
||||||
bitcoind: BitcoindRpcClient,
|
bitcoind: BitcoindRpcClient,
|
||||||
nodeApi: NodeApi,
|
nodeApi: NodeApi,
|
||||||
feeProvider: FeeRateApi)(implicit
|
feeProvider: FeeRateApi
|
||||||
|
)(implicit
|
||||||
override val conf: BitcoinSAppConfig,
|
override val conf: BitcoinSAppConfig,
|
||||||
override val system: ActorSystem)
|
override val system: ActorSystem
|
||||||
extends DLCWalletLoaderApi {
|
) extends DLCWalletLoaderApi {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
implicit private val nodeConf: NodeAppConfig = conf.nodeConf
|
implicit private val nodeConf: NodeAppConfig = conf.nodeConf
|
||||||
|
|
||||||
override def load(
|
override def load(
|
||||||
walletNameOpt: Option[String],
|
walletNameOpt: Option[String],
|
||||||
aesPasswordOpt: Option[AesPassword]): Future[
|
aesPasswordOpt: Option[AesPassword]
|
||||||
(WalletHolder, WalletAppConfig, DLCAppConfig)] = {
|
): Future[(WalletHolder, WalletAppConfig, DLCAppConfig)] = {
|
||||||
val stopCallbackF = nodeConf.callBacks match {
|
val stopCallbackF = nodeConf.callBacks match {
|
||||||
case stream: NodeCallbackStreamManager =>
|
case stream: NodeCallbackStreamManager =>
|
||||||
stream.stop()
|
stream.stop()
|
||||||
@ -347,15 +364,17 @@ case class DLCWalletBitcoindBackendLoader(
|
|||||||
nodeApi = nodeApi,
|
nodeApi = nodeApi,
|
||||||
feeProviderApi = feeProvider,
|
feeProviderApi = feeProvider,
|
||||||
walletNameOpt = walletNameOpt,
|
walletNameOpt = walletNameOpt,
|
||||||
aesPasswordOpt = aesPasswordOpt)
|
aesPasswordOpt = aesPasswordOpt
|
||||||
|
)
|
||||||
|
|
||||||
_ <- stopOldWalletAppConfig(walletConfig)
|
_ <- stopOldWalletAppConfig(walletConfig)
|
||||||
_ <- stopOldDLCAppConfig(dlcConfig)
|
_ <- stopOldDLCAppConfig(dlcConfig)
|
||||||
nodeCallbacks <- CallbackUtil.createBitcoindNodeCallbacksForWallet(
|
nodeCallbacks <- CallbackUtil.createBitcoindNodeCallbacksForWallet(
|
||||||
walletHolder)
|
walletHolder
|
||||||
|
)
|
||||||
_ = nodeConf.replaceCallbacks(nodeCallbacks)
|
_ = nodeConf.replaceCallbacks(nodeCallbacks)
|
||||||
_ <- walletHolder.replaceWallet(dlcWallet)
|
_ <- walletHolder.replaceWallet(dlcWallet)
|
||||||
//do something with possible rescan?
|
// do something with possible rescan?
|
||||||
rescanState <- restartRescanIfNeeded(walletHolder)
|
rescanState <- restartRescanIfNeeded(walletHolder)
|
||||||
_ = setRescanState(rescanState)
|
_ = setRescanState(rescanState)
|
||||||
} yield {
|
} yield {
|
||||||
|
@ -45,7 +45,9 @@ object DecodeAccept extends ServerJsonModels {
|
|||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length} Expected: 1"))
|
s"Bad number of arguments: ${other.length} Expected: 1"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,7 +77,9 @@ object DecodeSign extends ServerJsonModels {
|
|||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length} Expected: 1"))
|
s"Bad number of arguments: ${other.length} Expected: 1"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,7 +101,9 @@ object DecodeAttestations extends ServerJsonModels {
|
|||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length}. Expected: 1"))
|
s"Bad number of arguments: ${other.length}. Expected: 1"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,7 +112,8 @@ case class DLCDataFromFile(
|
|||||||
path: Path,
|
path: Path,
|
||||||
destinationOpt: Option[Path],
|
destinationOpt: Option[Path],
|
||||||
externalPayoutAddressOpt: Option[BitcoinAddress],
|
externalPayoutAddressOpt: Option[BitcoinAddress],
|
||||||
externalChangeAddressOpt: Option[BitcoinAddress])
|
externalChangeAddressOpt: Option[BitcoinAddress]
|
||||||
|
)
|
||||||
|
|
||||||
object DLCDataFromFile extends ServerJsonModels {
|
object DLCDataFromFile extends ServerJsonModels {
|
||||||
|
|
||||||
@ -115,7 +122,8 @@ object DLCDataFromFile extends ServerJsonModels {
|
|||||||
pathJs: Value,
|
pathJs: Value,
|
||||||
destJs: Value,
|
destJs: Value,
|
||||||
payoutAddressJs: Value,
|
payoutAddressJs: Value,
|
||||||
changeAddressJs: Value) = Try {
|
changeAddressJs: Value
|
||||||
|
) = Try {
|
||||||
val path = new File(pathJs.str).toPath
|
val path = new File(pathJs.str).toPath
|
||||||
val destJsOpt = nullToOpt(destJs)
|
val destJsOpt = nullToOpt(destJs)
|
||||||
val destOpt = destJsOpt.map(js => new File(js.str).toPath)
|
val destOpt = destJsOpt.map(js => new File(js.str).toPath)
|
||||||
@ -143,7 +151,9 @@ object DLCDataFromFile extends ServerJsonModels {
|
|||||||
case other =>
|
case other =>
|
||||||
Failure(
|
Failure(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Bad number of arguments: ${other.length}. Expected: 1"))
|
s"Bad number of arguments: ${other.length}. Expected: 1"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,7 +161,8 @@ object DLCDataFromFile extends ServerJsonModels {
|
|||||||
case class OfferAdd(
|
case class OfferAdd(
|
||||||
offerTLV: DLCOfferTLV,
|
offerTLV: DLCOfferTLV,
|
||||||
peer: Option[String],
|
peer: Option[String],
|
||||||
message: Option[String])
|
message: Option[String]
|
||||||
|
)
|
||||||
|
|
||||||
object OfferAdd extends ServerJsonModels {
|
object OfferAdd extends ServerJsonModels {
|
||||||
|
|
||||||
@ -167,7 +178,8 @@ object OfferAdd extends ServerJsonModels {
|
|||||||
}
|
}
|
||||||
case other =>
|
case other =>
|
||||||
val exn = new IllegalArgumentException(
|
val exn = new IllegalArgumentException(
|
||||||
s"Bad number or arguments to offer-add, got=${other.length} expected=3")
|
s"Bad number or arguments to offer-add, got=${other.length} expected=3"
|
||||||
|
)
|
||||||
Failure(exn)
|
Failure(exn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,7 +198,8 @@ object OfferRemove {
|
|||||||
}
|
}
|
||||||
case other =>
|
case other =>
|
||||||
val exn = new IllegalArgumentException(
|
val exn = new IllegalArgumentException(
|
||||||
s"Bad number or arguments to offer-remove, got=${other.length} expected=1")
|
s"Bad number or arguments to offer-remove, got=${other.length} expected=1"
|
||||||
|
)
|
||||||
Failure(exn)
|
Failure(exn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,7 +208,8 @@ object OfferRemove {
|
|||||||
case class OfferSend(
|
case class OfferSend(
|
||||||
remoteAddress: InetSocketAddress,
|
remoteAddress: InetSocketAddress,
|
||||||
message: String,
|
message: String,
|
||||||
offerE: Either[DLCOfferTLV, Sha256Digest])
|
offerE: Either[DLCOfferTLV, Sha256Digest]
|
||||||
|
)
|
||||||
|
|
||||||
object OfferSend extends ServerJsonModels {
|
object OfferSend extends ServerJsonModels {
|
||||||
|
|
||||||
@ -216,7 +230,8 @@ object OfferSend extends ServerJsonModels {
|
|||||||
}
|
}
|
||||||
case other =>
|
case other =>
|
||||||
val exn = new IllegalArgumentException(
|
val exn = new IllegalArgumentException(
|
||||||
s"Bad number or arguments to offer-send, got=${other.length} expected=3")
|
s"Bad number or arguments to offer-send, got=${other.length} expected=3"
|
||||||
|
)
|
||||||
Failure(exn)
|
Failure(exn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,7 +251,8 @@ object GetDLCOffer {
|
|||||||
}
|
}
|
||||||
case other =>
|
case other =>
|
||||||
val exn = new IllegalArgumentException(
|
val exn = new IllegalArgumentException(
|
||||||
s"Bad number or arguments to offer-send, got=${other.length} expected=1")
|
s"Bad number or arguments to offer-send, got=${other.length} expected=1"
|
||||||
|
)
|
||||||
Failure(exn)
|
Failure(exn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,7 +267,8 @@ trait ServerJsonModels {
|
|||||||
case _: Value =>
|
case _: Value =>
|
||||||
throw Value.InvalidData(
|
throw Value.InvalidData(
|
||||||
js,
|
js,
|
||||||
"Expected an OracleAnnouncementTLV as a hex string")
|
"Expected an OracleAnnouncementTLV as a hex string"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def jsToContractInfoTLV(js: Value): ContractInfoV0TLV =
|
def jsToContractInfoTLV(js: Value): ContractInfoV0TLV =
|
||||||
@ -311,7 +328,8 @@ trait ServerJsonModels {
|
|||||||
LockUnspentOutputParameter.fromJson(js)
|
LockUnspentOutputParameter.fromJson(js)
|
||||||
|
|
||||||
def jsToLockUnspentOutputParameters(
|
def jsToLockUnspentOutputParameters(
|
||||||
js: Value): Seq[LockUnspentOutputParameter] = {
|
js: Value
|
||||||
|
): Seq[LockUnspentOutputParameter] = {
|
||||||
js.arr.foldLeft(Seq.empty[LockUnspentOutputParameter])((seq, outPoint) =>
|
js.arr.foldLeft(Seq.empty[LockUnspentOutputParameter])((seq, outPoint) =>
|
||||||
seq :+ jsToLockUnspentOutputParameter(outPoint))
|
seq :+ jsToLockUnspentOutputParameter(outPoint))
|
||||||
}
|
}
|
||||||
@ -337,11 +355,13 @@ trait ServerJsonModels {
|
|||||||
case _: Value =>
|
case _: Value =>
|
||||||
throw Value.InvalidData(
|
throw Value.InvalidData(
|
||||||
js,
|
js,
|
||||||
"Expected a SchnorrDigitalSignature as a hex string")
|
"Expected a SchnorrDigitalSignature as a hex string"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def jsToSchnorrDigitalSignatureVec(
|
def jsToSchnorrDigitalSignatureVec(
|
||||||
js: Value): Vector[SchnorrDigitalSignature] = {
|
js: Value
|
||||||
|
): Vector[SchnorrDigitalSignature] = {
|
||||||
js.arr.foldLeft(Vector.empty[SchnorrDigitalSignature])((vec, sig) =>
|
js.arr.foldLeft(Vector.empty[SchnorrDigitalSignature])((vec, sig) =>
|
||||||
vec :+ jsToSchnorrDigitalSignature(sig))
|
vec :+ jsToSchnorrDigitalSignature(sig))
|
||||||
}
|
}
|
||||||
@ -353,7 +373,8 @@ trait ServerJsonModels {
|
|||||||
case _: Value =>
|
case _: Value =>
|
||||||
throw Value.InvalidData(
|
throw Value.InvalidData(
|
||||||
js,
|
js,
|
||||||
"Expected a OracleAttestmentTLV as a hex string")
|
"Expected a OracleAttestmentTLV as a hex string"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def jsToOracleAttestmentTLVVec(js: Value): Vector[OracleAttestmentTLV] = {
|
def jsToOracleAttestmentTLVVec(js: Value): Vector[OracleAttestmentTLV] = {
|
||||||
@ -384,7 +405,8 @@ trait ServerJsonModels {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def jsToWalletNameAndPassword(
|
def jsToWalletNameAndPassword(
|
||||||
js: Value): (Option[String], Option[AesPassword]) = {
|
js: Value
|
||||||
|
): (Option[String], Option[AesPassword]) = {
|
||||||
js match {
|
js match {
|
||||||
case Arr(arr) =>
|
case Arr(arr) =>
|
||||||
if (arr.size >= 2) {
|
if (arr.size >= 2) {
|
||||||
@ -403,14 +425,16 @@ trait ServerJsonModels {
|
|||||||
case Arr(arr) => arr.map(_.str).toVector
|
case Arr(arr) => arr.map(_.str).toVector
|
||||||
case Null | False | True | Num(_) | Obj(_) =>
|
case Null | False | True | Num(_) | Obj(_) =>
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"mnemonic must be a string or array of strings")
|
"mnemonic must be a string or array of strings"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
MnemonicCode.fromWords(mnemonicWords)
|
MnemonicCode.fromWords(mnemonicWords)
|
||||||
}
|
}
|
||||||
|
|
||||||
def jsToInetSocketAddress(
|
def jsToInetSocketAddress(
|
||||||
js: Value,
|
js: Value,
|
||||||
defaultPort: Int = -1): InetSocketAddress = {
|
defaultPort: Int = -1
|
||||||
|
): InetSocketAddress = {
|
||||||
js match {
|
js match {
|
||||||
case str: Str =>
|
case str: Str =>
|
||||||
val uri = new URI("tcp://" + str.str)
|
val uri = new URI("tcp://" + str.str)
|
||||||
|
@ -37,8 +37,8 @@ import scala.util.{Failure, Success}
|
|||||||
|
|
||||||
case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
||||||
system: ActorSystem,
|
system: ActorSystem,
|
||||||
walletConf: WalletAppConfig)
|
walletConf: WalletAppConfig
|
||||||
extends ServerRoute
|
) extends ServerRoute
|
||||||
with BitcoinSLogger {
|
with BitcoinSLogger {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
|
|
||||||
@ -64,7 +64,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
|
|
||||||
private def handleBroadcastable(
|
private def handleBroadcastable(
|
||||||
tx: Transaction,
|
tx: Transaction,
|
||||||
noBroadcast: Boolean): Future[NetworkElement] = {
|
noBroadcast: Boolean
|
||||||
|
): Future[NetworkElement] = {
|
||||||
if (noBroadcast) {
|
if (noBroadcast) {
|
||||||
Future.successful(tx)
|
Future.successful(tx)
|
||||||
} else {
|
} else {
|
||||||
@ -154,11 +155,14 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
|
|
||||||
val json = Obj(
|
val json = Obj(
|
||||||
"confirmed" -> Num(
|
"confirmed" -> Num(
|
||||||
formatCurrencyUnit(confirmed, isSats).toDouble),
|
formatCurrencyUnit(confirmed, isSats).toDouble
|
||||||
|
),
|
||||||
"unconfirmed" -> Num(
|
"unconfirmed" -> Num(
|
||||||
formatCurrencyUnit(unconfirmed, isSats).toDouble),
|
formatCurrencyUnit(unconfirmed, isSats).toDouble
|
||||||
|
),
|
||||||
"reserved" -> Num(
|
"reserved" -> Num(
|
||||||
formatCurrencyUnit(reserved, isSats).toDouble),
|
formatCurrencyUnit(reserved, isSats).toDouble
|
||||||
|
),
|
||||||
"total" -> Num(formatCurrencyUnit(total, isSats).toDouble)
|
"total" -> Num(formatCurrencyUnit(total, isSats).toDouble)
|
||||||
)
|
)
|
||||||
Server.httpSuccess(json)
|
Server.httpSuccess(json)
|
||||||
@ -226,7 +230,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
complete {
|
complete {
|
||||||
wallet.tagAddress(address, label).map { tagDb =>
|
wallet.tagAddress(address, label).map { tagDb =>
|
||||||
Server.httpSuccess(
|
Server.httpSuccess(
|
||||||
s"Added label \'${tagDb.tagName.name}\' to ${tagDb.address.value}")
|
s"Added label \'${tagDb.tagName.name}\' to ${tagDb.address.value}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -263,8 +268,10 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
val json: Vector[ujson.Obj] = grouped.map { case (address, labels) =>
|
val json: Vector[ujson.Obj] = grouped.map { case (address, labels) =>
|
||||||
val tagNames: Vector[ujson.Str] =
|
val tagNames: Vector[ujson.Str] =
|
||||||
labels.map(l => ujson.Str(l.tagName.name))
|
labels.map(l => ujson.Str(l.tagName.name))
|
||||||
ujson.Obj(("address", address.toString),
|
ujson.Obj(
|
||||||
("labels", ujson.Arr.from(tagNames)))
|
("address", address.toString),
|
||||||
|
("labels", ujson.Arr.from(tagNames))
|
||||||
|
)
|
||||||
}.toVector
|
}.toVector
|
||||||
Server.httpSuccess(ujson.Arr.from(json))
|
Server.httpSuccess(ujson.Arr.from(json))
|
||||||
}
|
}
|
||||||
@ -298,11 +305,15 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
dlcOpt <- wallet.findDLCByTemporaryContractId(tempContractId)
|
dlcOpt <- wallet.findDLCByTemporaryContractId(tempContractId)
|
||||||
dlc = dlcOpt.getOrElse(
|
dlc = dlcOpt.getOrElse(
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
s"Cannot find a DLC with temp contact ID $tempContractId"))
|
s"Cannot find a DLC with temp contact ID $tempContractId"
|
||||||
|
)
|
||||||
|
)
|
||||||
offerOpt <- wallet.getDLCOffer(dlc.dlcId)
|
offerOpt <- wallet.getDLCOffer(dlc.dlcId)
|
||||||
offer = offerOpt.getOrElse(
|
offer = offerOpt.getOrElse(
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
s"Cannot find an offer with for DLC ID ${dlc.dlcId}"))
|
s"Cannot find an offer with for DLC ID ${dlc.dlcId}"
|
||||||
|
)
|
||||||
|
)
|
||||||
} yield {
|
} yield {
|
||||||
Server.httpSuccess(offer.toMessage.hex)
|
Server.httpSuccess(offer.toMessage.hex)
|
||||||
}
|
}
|
||||||
@ -358,14 +369,17 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
case Failure(exception) =>
|
case Failure(exception) =>
|
||||||
complete(Server.httpBadRequest(exception))
|
complete(Server.httpBadRequest(exception))
|
||||||
case Success(
|
case Success(
|
||||||
CreateDLCOffer(contractInfo,
|
CreateDLCOffer(
|
||||||
collateral,
|
contractInfo,
|
||||||
feeRateOpt,
|
collateral,
|
||||||
locktimeOpt,
|
feeRateOpt,
|
||||||
refundLT,
|
locktimeOpt,
|
||||||
payoutAddressOpt,
|
refundLT,
|
||||||
changeAddressOpt,
|
payoutAddressOpt,
|
||||||
peerAddressOpt)) =>
|
changeAddressOpt,
|
||||||
|
peerAddressOpt
|
||||||
|
)
|
||||||
|
) =>
|
||||||
complete {
|
complete {
|
||||||
val announcements = contractInfo.oracleInfo match {
|
val announcements = contractInfo.oracleInfo match {
|
||||||
case OracleInfoV0TLV(announcement) => Vector(announcement)
|
case OracleInfoV0TLV(announcement) => Vector(announcement)
|
||||||
@ -375,29 +389,34 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
if (!announcements.forall(_.validateSignature)) {
|
if (!announcements.forall(_.validateSignature)) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
s"Received Oracle announcement with invalid signature! ${announcements
|
s"Received Oracle announcement with invalid signature! ${announcements
|
||||||
.map(_.hex)}")
|
.map(_.hex)}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val offerF = locktimeOpt match {
|
val offerF = locktimeOpt match {
|
||||||
case Some(locktime) =>
|
case Some(locktime) =>
|
||||||
wallet
|
wallet
|
||||||
.createDLCOffer(contractInfo,
|
.createDLCOffer(
|
||||||
collateral,
|
contractInfo,
|
||||||
feeRateOpt,
|
collateral,
|
||||||
locktime,
|
feeRateOpt,
|
||||||
refundLT,
|
locktime,
|
||||||
peerAddressOpt,
|
refundLT,
|
||||||
payoutAddressOpt,
|
peerAddressOpt,
|
||||||
changeAddressOpt)
|
payoutAddressOpt,
|
||||||
|
changeAddressOpt
|
||||||
|
)
|
||||||
case None =>
|
case None =>
|
||||||
wallet
|
wallet
|
||||||
.createDLCOffer(contractInfo,
|
.createDLCOffer(
|
||||||
collateral,
|
contractInfo,
|
||||||
feeRateOpt,
|
collateral,
|
||||||
refundLT,
|
feeRateOpt,
|
||||||
peerAddressOpt,
|
refundLT,
|
||||||
payoutAddressOpt,
|
peerAddressOpt,
|
||||||
changeAddressOpt)
|
payoutAddressOpt,
|
||||||
|
changeAddressOpt
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
offerF.map { offer =>
|
offerF.map { offer =>
|
||||||
@ -411,16 +430,21 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
case Failure(exception) =>
|
case Failure(exception) =>
|
||||||
complete(Server.httpBadRequest(exception))
|
complete(Server.httpBadRequest(exception))
|
||||||
case Success(
|
case Success(
|
||||||
AcceptDLCOffer(offer,
|
AcceptDLCOffer(
|
||||||
payoutAddressOpt,
|
offer,
|
||||||
changeAddressOpt,
|
payoutAddressOpt,
|
||||||
peerAddressOpt)) =>
|
changeAddressOpt,
|
||||||
|
peerAddressOpt
|
||||||
|
)
|
||||||
|
) =>
|
||||||
complete {
|
complete {
|
||||||
wallet
|
wallet
|
||||||
.acceptDLCOffer(offer.tlv,
|
.acceptDLCOffer(
|
||||||
peerAddressOpt,
|
offer.tlv,
|
||||||
payoutAddressOpt,
|
peerAddressOpt,
|
||||||
changeAddressOpt)
|
payoutAddressOpt,
|
||||||
|
changeAddressOpt
|
||||||
|
)
|
||||||
.map { accept =>
|
.map { accept =>
|
||||||
Server.httpSuccess(accept.toMessage.hex)
|
Server.httpSuccess(accept.toMessage.hex)
|
||||||
}
|
}
|
||||||
@ -432,10 +456,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
case Failure(exception) =>
|
case Failure(exception) =>
|
||||||
complete(Server.httpBadRequest(exception))
|
complete(Server.httpBadRequest(exception))
|
||||||
case Success(
|
case Success(
|
||||||
DLCDataFromFile(path,
|
DLCDataFromFile(path, destOpt, payoutAddressOpt, changeAddressOpt)
|
||||||
destOpt,
|
) =>
|
||||||
payoutAddressOpt,
|
|
||||||
changeAddressOpt)) =>
|
|
||||||
complete {
|
complete {
|
||||||
|
|
||||||
val hex = Files.readAllLines(path).get(0)
|
val hex = Files.readAllLines(path).get(0)
|
||||||
@ -445,10 +467,12 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
.getOrElse(LnMessage(DLCOfferTLV.fromHex(hex)))
|
.getOrElse(LnMessage(DLCOfferTLV.fromHex(hex)))
|
||||||
|
|
||||||
wallet
|
wallet
|
||||||
.acceptDLCOffer(offerMessage.tlv,
|
.acceptDLCOffer(
|
||||||
None,
|
offerMessage.tlv,
|
||||||
payoutAddressOpt,
|
None,
|
||||||
changeAddressOpt)
|
payoutAddressOpt,
|
||||||
|
changeAddressOpt
|
||||||
|
)
|
||||||
.map { accept =>
|
.map { accept =>
|
||||||
val ret = handleDestinationOpt(accept.toMessage.hex, destOpt)
|
val ret = handleDestinationOpt(accept.toMessage.hex, destOpt)
|
||||||
Server.httpSuccess(ret)
|
Server.httpSuccess(ret)
|
||||||
@ -500,7 +524,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
complete {
|
complete {
|
||||||
wallet.addDLCSigs(sigs.tlv).map { db =>
|
wallet.addDLCSigs(sigs.tlv).map { db =>
|
||||||
Server.httpSuccess(
|
Server.httpSuccess(
|
||||||
s"Successfully added sigs to DLC ${db.contractIdOpt.get.toHex}")
|
s"Successfully added sigs to DLC ${db.contractIdOpt.get.toHex}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -520,7 +545,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
|
|
||||||
wallet.addDLCSigs(signMessage.tlv).map { db =>
|
wallet.addDLCSigs(signMessage.tlv).map { db =>
|
||||||
Server.httpSuccess(
|
Server.httpSuccess(
|
||||||
s"Successfully added sigs to DLC ${db.contractIdOpt.get.toHex}")
|
s"Successfully added sigs to DLC ${db.contractIdOpt.get.toHex}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -604,7 +630,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
Server.httpSuccess(ret)
|
Server.httpSuccess(ret)
|
||||||
case None =>
|
case None =>
|
||||||
Server.httpError(
|
Server.httpError(
|
||||||
s"Cannot execute DLC with contractId=${contractId.toHex}")
|
s"Cannot execute DLC with contractId=${contractId.toHex}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -627,15 +654,19 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
|
|
||||||
case ServerCommand("sendtoaddress", arr) =>
|
case ServerCommand("sendtoaddress", arr) =>
|
||||||
withValidServerCommand(SendToAddress.fromJsArr(arr)) {
|
withValidServerCommand(SendToAddress.fromJsArr(arr)) {
|
||||||
case SendToAddress(address,
|
case SendToAddress(
|
||||||
bitcoins,
|
address,
|
||||||
satoshisPerVirtualByteOpt,
|
bitcoins,
|
||||||
noBroadcast) =>
|
satoshisPerVirtualByteOpt,
|
||||||
|
noBroadcast
|
||||||
|
) =>
|
||||||
complete {
|
complete {
|
||||||
for {
|
for {
|
||||||
tx <- wallet.sendToAddress(address,
|
tx <- wallet.sendToAddress(
|
||||||
bitcoins,
|
address,
|
||||||
satoshisPerVirtualByteOpt)
|
bitcoins,
|
||||||
|
satoshisPerVirtualByteOpt
|
||||||
|
)
|
||||||
retStr <- handleBroadcastable(tx, noBroadcast)
|
retStr <- handleBroadcastable(tx, noBroadcast)
|
||||||
} yield {
|
} yield {
|
||||||
Server.httpSuccess(retStr.hex)
|
Server.httpSuccess(retStr.hex)
|
||||||
@ -644,16 +675,20 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
}
|
}
|
||||||
case ServerCommand("sendfromoutpoints", arr) =>
|
case ServerCommand("sendfromoutpoints", arr) =>
|
||||||
withValidServerCommand(SendFromOutPoints.fromJsArr(arr)) {
|
withValidServerCommand(SendFromOutPoints.fromJsArr(arr)) {
|
||||||
case SendFromOutPoints(outPoints,
|
case SendFromOutPoints(
|
||||||
address,
|
outPoints,
|
||||||
bitcoins,
|
address,
|
||||||
satoshisPerVirtualByteOpt) =>
|
bitcoins,
|
||||||
|
satoshisPerVirtualByteOpt
|
||||||
|
) =>
|
||||||
complete {
|
complete {
|
||||||
for {
|
for {
|
||||||
tx <- wallet.sendFromOutPoints(outPoints,
|
tx <- wallet.sendFromOutPoints(
|
||||||
address,
|
outPoints,
|
||||||
bitcoins,
|
address,
|
||||||
satoshisPerVirtualByteOpt)
|
bitcoins,
|
||||||
|
satoshisPerVirtualByteOpt
|
||||||
|
)
|
||||||
_ <- wallet.broadcastTransaction(tx)
|
_ <- wallet.broadcastTransaction(tx)
|
||||||
} yield Server.httpSuccess(tx.txIdBE)
|
} yield Server.httpSuccess(tx.txIdBE)
|
||||||
}
|
}
|
||||||
@ -675,10 +710,12 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
case SendWithAlgo(address, bitcoins, satoshisPerVirtualByteOpt, algo) =>
|
case SendWithAlgo(address, bitcoins, satoshisPerVirtualByteOpt, algo) =>
|
||||||
complete {
|
complete {
|
||||||
for {
|
for {
|
||||||
tx <- wallet.sendWithAlgo(address,
|
tx <- wallet.sendWithAlgo(
|
||||||
bitcoins,
|
address,
|
||||||
satoshisPerVirtualByteOpt,
|
bitcoins,
|
||||||
algo)
|
satoshisPerVirtualByteOpt,
|
||||||
|
algo
|
||||||
|
)
|
||||||
_ <- wallet.broadcastTransaction(tx)
|
_ <- wallet.broadcastTransaction(tx)
|
||||||
} yield Server.httpSuccess(tx.txIdBE)
|
} yield Server.httpSuccess(tx.txIdBE)
|
||||||
}
|
}
|
||||||
@ -698,9 +735,11 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
case OpReturnCommit(message, hashMessage, satoshisPerVirtualByteOpt) =>
|
case OpReturnCommit(message, hashMessage, satoshisPerVirtualByteOpt) =>
|
||||||
complete {
|
complete {
|
||||||
for {
|
for {
|
||||||
tx <- wallet.makeOpReturnCommitment(message,
|
tx <- wallet.makeOpReturnCommitment(
|
||||||
hashMessage,
|
message,
|
||||||
satoshisPerVirtualByteOpt)
|
hashMessage,
|
||||||
|
satoshisPerVirtualByteOpt
|
||||||
|
)
|
||||||
_ <- wallet.broadcastTransaction(tx)
|
_ <- wallet.broadcastTransaction(tx)
|
||||||
} yield {
|
} yield {
|
||||||
Server.httpSuccess(tx.txIdBE)
|
Server.httpSuccess(tx.txIdBE)
|
||||||
@ -838,9 +877,11 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
case KeyManagerPassphraseChange(oldPassword, newPassword) =>
|
case KeyManagerPassphraseChange(oldPassword, newPassword) =>
|
||||||
complete {
|
complete {
|
||||||
val path = walletConf.seedPath
|
val path = walletConf.seedPath
|
||||||
WalletStorage.changeAesPassword(path,
|
WalletStorage.changeAesPassword(
|
||||||
Some(oldPassword),
|
path,
|
||||||
Some(newPassword))
|
Some(oldPassword),
|
||||||
|
Some(newPassword)
|
||||||
|
)
|
||||||
|
|
||||||
Server.httpSuccess(ujson.Null)
|
Server.httpSuccess(ujson.Null)
|
||||||
}
|
}
|
||||||
@ -867,16 +908,20 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
|
|
||||||
val mnemonicState = passwordOpt match {
|
val mnemonicState = passwordOpt match {
|
||||||
case Some(pass) =>
|
case Some(pass) =>
|
||||||
DecryptedMnemonic(mnemonic,
|
DecryptedMnemonic(
|
||||||
creationTime,
|
mnemonic,
|
||||||
backupTimeOpt = None,
|
creationTime,
|
||||||
imported = true)
|
backupTimeOpt = None,
|
||||||
|
imported = true
|
||||||
|
)
|
||||||
.encrypt(pass)
|
.encrypt(pass)
|
||||||
case None =>
|
case None =>
|
||||||
DecryptedMnemonic(mnemonic,
|
DecryptedMnemonic(
|
||||||
creationTime,
|
mnemonic,
|
||||||
backupTimeOpt = None,
|
creationTime,
|
||||||
imported = true)
|
backupTimeOpt = None,
|
||||||
|
imported = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletStorage.writeSeedToDisk(seedPath, mnemonicState)
|
WalletStorage.writeSeedToDisk(seedPath, mnemonicState)
|
||||||
@ -894,7 +939,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
Server.httpSuccess(
|
Server.httpSuccess(
|
||||||
WalletStorage
|
WalletStorage
|
||||||
.readDecryptedSeedPhraseForBackup(seedPath, passwordOpt)
|
.readDecryptedSeedPhraseForBackup(seedPath, passwordOpt)
|
||||||
.get)
|
.get
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -938,16 +984,20 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
|
|
||||||
val mnemonicState = passwordOpt match {
|
val mnemonicState = passwordOpt match {
|
||||||
case Some(pass) =>
|
case Some(pass) =>
|
||||||
DecryptedExtPrivKey(xprv,
|
DecryptedExtPrivKey(
|
||||||
creationTime,
|
xprv,
|
||||||
backupTimeOpt = None,
|
creationTime,
|
||||||
imported = true)
|
backupTimeOpt = None,
|
||||||
|
imported = true
|
||||||
|
)
|
||||||
.encrypt(pass)
|
.encrypt(pass)
|
||||||
case None =>
|
case None =>
|
||||||
DecryptedExtPrivKey(xprv,
|
DecryptedExtPrivKey(
|
||||||
creationTime,
|
xprv,
|
||||||
backupTimeOpt = None,
|
creationTime,
|
||||||
imported = true)
|
backupTimeOpt = None,
|
||||||
|
imported = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletStorage.writeSeedToDisk(seedPath, mnemonicState)
|
WalletStorage.writeSeedToDisk(seedPath, mnemonicState)
|
||||||
@ -973,7 +1023,7 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
|
|
||||||
feeRateF.map { f =>
|
feeRateF.map { f =>
|
||||||
logger.info(s"Retrieved fee rate ${f.toSatsPerVByte}, it took ${System
|
logger.info(s"Retrieved fee rate ${f.toSatsPerVByte}, it took ${System
|
||||||
.currentTimeMillis() - start}ms")
|
.currentTimeMillis() - start}ms")
|
||||||
Server.httpSuccess(f.toSatsPerVByte)
|
Server.httpSuccess(f.toSatsPerVByte)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1020,7 +1070,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
.map(_ + "-")
|
.map(_ + "-")
|
||||||
.getOrElse(WalletAppConfig.DEFAULT_WALLET_NAME)
|
.getOrElse(WalletAppConfig.DEFAULT_WALLET_NAME)
|
||||||
kmConf.seedFolder.resolve(
|
kmConf.seedFolder.resolve(
|
||||||
walletName + WalletStorage.ENCRYPTED_SEED_FILE_NAME)
|
walletName + WalletStorage.ENCRYPTED_SEED_FILE_NAME
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns information about the state of our wallet */
|
/** Returns information about the state of our wallet */
|
||||||
@ -1048,7 +1099,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
|
|
||||||
private def formatCurrencyUnit(
|
private def formatCurrencyUnit(
|
||||||
currencyUnit: CurrencyUnit,
|
currencyUnit: CurrencyUnit,
|
||||||
isSats: Boolean): Double = {
|
isSats: Boolean
|
||||||
|
): Double = {
|
||||||
if (isSats) {
|
if (isSats) {
|
||||||
currencyUnit.satoshis.toBigDecimal.toDouble
|
currencyUnit.satoshis.toBigDecimal.toDouble
|
||||||
} else {
|
} else {
|
||||||
@ -1066,19 +1118,21 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the fee rate for the wallet with a timeout on the request of 1 second */
|
/** Gets the fee rate for the wallet with a timeout on the request of 1 second
|
||||||
|
*/
|
||||||
private def getFeeRate(): Future[FeeUnit] = {
|
private def getFeeRate(): Future[FeeUnit] = {
|
||||||
val resultF = wallet
|
val resultF = wallet
|
||||||
.getFeeRate()
|
.getFeeRate()
|
||||||
.recover { case scala.util.control.NonFatal(exn) =>
|
.recover { case scala.util.control.NonFatal(exn) =>
|
||||||
logger.error(
|
logger.error(
|
||||||
s"Failed to fetch fee rate from wallet, returning -1 sats/vbyte",
|
s"Failed to fetch fee rate from wallet, returning -1 sats/vbyte",
|
||||||
exn)
|
exn
|
||||||
|
)
|
||||||
SatoshisPerVirtualByte.negativeOne
|
SatoshisPerVirtualByte.negativeOne
|
||||||
}
|
}
|
||||||
//due to tor variability, we need to make sure we give a prompt response.
|
// due to tor variability, we need to make sure we give a prompt response.
|
||||||
//timeout the fee rate request after 1 second
|
// timeout the fee rate request after 1 second
|
||||||
//see: https://github.com/bitcoin-s/bitcoin-s/issues/4460#issuecomment-1182325014
|
// see: https://github.com/bitcoin-s/bitcoin-s/issues/4460#issuecomment-1182325014
|
||||||
try {
|
try {
|
||||||
val result = Await.result(resultF, 1.second)
|
val result = Await.result(resultF, 1.second)
|
||||||
Future.successful(result)
|
Future.successful(result)
|
||||||
@ -1097,15 +1151,15 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
val stateF: Future[RescanState] = rescanState match {
|
val stateF: Future[RescanState] = rescanState match {
|
||||||
case started: RescanState.RescanStarted =>
|
case started: RescanState.RescanStarted =>
|
||||||
if (started.isStopped) {
|
if (started.isStopped) {
|
||||||
//means rescan is done, reset the variable
|
// means rescan is done, reset the variable
|
||||||
rescanStateOpt = Some(RescanDone)
|
rescanStateOpt = Some(RescanDone)
|
||||||
Future.successful(RescanDone)
|
Future.successful(RescanDone)
|
||||||
} else {
|
} else {
|
||||||
//do nothing, we don't want to reset/stop a rescan that is running
|
// do nothing, we don't want to reset/stop a rescan that is running
|
||||||
Future.successful(started)
|
Future.successful(started)
|
||||||
}
|
}
|
||||||
case RescanState.RescanDone | RescanState.RescanNotNeeded =>
|
case RescanState.RescanDone | RescanState.RescanNotNeeded =>
|
||||||
//if the previous rescan is done, start another rescan
|
// if the previous rescan is done, start another rescan
|
||||||
startRescan(rescan)
|
startRescan(rescan)
|
||||||
case RescanState.RescanAlreadyStarted =>
|
case RescanState.RescanAlreadyStarted =>
|
||||||
Future.successful(RescanState.RescanAlreadyStarted)
|
Future.successful(RescanState.RescanAlreadyStarted)
|
||||||
@ -1124,7 +1178,9 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
} else {
|
} else {
|
||||||
Future.failed(
|
Future.failed(
|
||||||
new IllegalArgumentException(
|
new IllegalArgumentException(
|
||||||
s"Cannot rescan when a rescan is already ongoing for wallet"))
|
s"Cannot rescan when a rescan is already ongoing for wallet"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1149,7 +1205,7 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit
|
|||||||
}
|
}
|
||||||
case RescanState.RescanAlreadyStarted | RescanState.RescanDone |
|
case RescanState.RescanAlreadyStarted | RescanState.RescanDone |
|
||||||
RescanState.RescanNotNeeded =>
|
RescanState.RescanNotNeeded =>
|
||||||
//do nothing in these cases, no state needs to be reset
|
// do nothing in these cases, no state needs to be reset
|
||||||
}
|
}
|
||||||
|
|
||||||
stateF
|
stateF
|
||||||
|
@ -7,8 +7,8 @@ import java.util.concurrent.atomic.AtomicBoolean
|
|||||||
|
|
||||||
case class WalletZmqSubscribers(
|
case class WalletZmqSubscribers(
|
||||||
rawTxSubscriberOpt: Option[ZMQSubscriber],
|
rawTxSubscriberOpt: Option[ZMQSubscriber],
|
||||||
rawBlockSubscriberOpt: Option[ZMQSubscriber])
|
rawBlockSubscriberOpt: Option[ZMQSubscriber]
|
||||||
extends StartStop[Unit] {
|
) extends StartStop[Unit] {
|
||||||
private val isStarted: AtomicBoolean = new AtomicBoolean(false)
|
private val isStarted: AtomicBoolean = new AtomicBoolean(false)
|
||||||
|
|
||||||
override def start(): Unit = {
|
override def start(): Unit = {
|
||||||
|
@ -4,12 +4,17 @@ import org.bitcoins.server.util.{BitcoindPollingCancellable}
|
|||||||
|
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
|
|
||||||
/** @param syncF the future that will be completed when the synchronization with bitcoind is complete
|
/** @param syncF
|
||||||
* @param pollingCancellable You can cancel bitcoind polling by calling [[BitcoindPollingCancellabe.cancel()]]
|
* the future that will be completed when the synchronization with bitcoind
|
||||||
|
* is complete
|
||||||
|
* @param pollingCancellable
|
||||||
|
* You can cancel bitcoind polling by calling
|
||||||
|
* [[BitcoindPollingCancellabe.cancel()]]
|
||||||
*/
|
*/
|
||||||
case class BitcoindSyncState(
|
case class BitcoindSyncState(
|
||||||
syncF: Future[Unit],
|
syncF: Future[Unit],
|
||||||
pollingCancellable: BitcoindPollingCancellable) {
|
pollingCancellable: BitcoindPollingCancellable
|
||||||
|
) {
|
||||||
|
|
||||||
/** Stops syncing and polling bitcoind */
|
/** Stops syncing and polling bitcoind */
|
||||||
def stop(): Future[Unit] = {
|
def stop(): Future[Unit] = {
|
||||||
|
@ -5,8 +5,8 @@ import org.bitcoins.commons.util.BitcoinSLogger
|
|||||||
|
|
||||||
case class BitcoindPollingCancellable(
|
case class BitcoindPollingCancellable(
|
||||||
blockPollingCancellable: Cancellable,
|
blockPollingCancellable: Cancellable,
|
||||||
mempoolPollingCancelable: Cancellable)
|
mempoolPollingCancelable: Cancellable
|
||||||
extends Cancellable
|
) extends Cancellable
|
||||||
with BitcoinSLogger {
|
with BitcoinSLogger {
|
||||||
|
|
||||||
override def cancel(): Boolean = {
|
override def cancel(): Boolean = {
|
||||||
@ -22,5 +22,6 @@ object BitcoindPollingCancellabe {
|
|||||||
|
|
||||||
val none: BitcoindPollingCancellable = BitcoindPollingCancellable(
|
val none: BitcoindPollingCancellable = BitcoindPollingCancellable(
|
||||||
Cancellable.alreadyCancelled,
|
Cancellable.alreadyCancelled,
|
||||||
Cancellable.alreadyCancelled)
|
Cancellable.alreadyCancelled
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ import scala.concurrent.Future
|
|||||||
object CallbackUtil extends BitcoinSLogger {
|
object CallbackUtil extends BitcoinSLogger {
|
||||||
|
|
||||||
def createNeutrinoNodeCallbacksForWallet(
|
def createNeutrinoNodeCallbacksForWallet(
|
||||||
wallet: WalletApi with NeutrinoWalletApi)(implicit
|
wallet: WalletApi with NeutrinoWalletApi
|
||||||
system: ActorSystem): Future[NodeCallbackStreamManager] = {
|
)(implicit system: ActorSystem): Future[NodeCallbackStreamManager] = {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
val txSink = Sink.foreachAsync[Transaction](1) { case tx: Transaction =>
|
val txSink = Sink.foreachAsync[Transaction](1) { case tx: Transaction =>
|
||||||
logger.debug(s"Receiving transaction txid=${tx.txIdBE.hex} as a callback")
|
logger.debug(s"Receiving transaction txid=${tx.txIdBE.hex} as a callback")
|
||||||
@ -32,7 +32,8 @@ object CallbackUtil extends BitcoinSLogger {
|
|||||||
Sink.foreachAsync[Vector[(DoubleSha256DigestBE, GolombFilter)]](1) {
|
Sink.foreachAsync[Vector[(DoubleSha256DigestBE, GolombFilter)]](1) {
|
||||||
case blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)] =>
|
case blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)] =>
|
||||||
logger.debug(
|
logger.debug(
|
||||||
s"Executing onCompactFilters callback with filter count=${blockFilters.length}")
|
s"Executing onCompactFilters callback with filter count=${blockFilters.length}"
|
||||||
|
)
|
||||||
wallet
|
wallet
|
||||||
.processCompactFilters(blockFilters = blockFilters)
|
.processCompactFilters(blockFilters = blockFilters)
|
||||||
.map(_ => ())
|
.map(_ => ())
|
||||||
@ -42,7 +43,8 @@ object CallbackUtil extends BitcoinSLogger {
|
|||||||
val blockSink = {
|
val blockSink = {
|
||||||
Sink.foreachAsync[Block](1) { case block: Block =>
|
Sink.foreachAsync[Block](1) { case block: Block =>
|
||||||
logger.debug(
|
logger.debug(
|
||||||
s"Executing onBlock callback=${block.blockHeader.hashBE.hex}")
|
s"Executing onBlock callback=${block.blockHeader.hashBE.hex}"
|
||||||
|
)
|
||||||
wallet.processBlock(block).map(_ => ())
|
wallet.processBlock(block).map(_ => ())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,7 +52,8 @@ object CallbackUtil extends BitcoinSLogger {
|
|||||||
val onHeaderSink = {
|
val onHeaderSink = {
|
||||||
Sink.foreachAsync(1) { headers: Vector[BlockHeader] =>
|
Sink.foreachAsync(1) { headers: Vector[BlockHeader] =>
|
||||||
logger.debug(
|
logger.debug(
|
||||||
s"Executing block header with header count=${headers.length}")
|
s"Executing block header with header count=${headers.length}"
|
||||||
|
)
|
||||||
if (headers.isEmpty) {
|
if (headers.isEmpty) {
|
||||||
Future.unit
|
Future.unit
|
||||||
} else {
|
} else {
|
||||||
@ -85,18 +88,20 @@ object CallbackUtil extends BitcoinSLogger {
|
|||||||
.map(_ => ())
|
.map(_ => ())
|
||||||
}
|
}
|
||||||
|
|
||||||
val callbacks = NodeCallbacks(onTxReceived = Vector(onTx),
|
val callbacks = NodeCallbacks(
|
||||||
onBlockReceived = Vector(onBlock),
|
onTxReceived = Vector(onTx),
|
||||||
onCompactFiltersReceived =
|
onBlockReceived = Vector(onBlock),
|
||||||
Vector(onCompactFilters),
|
onCompactFiltersReceived = Vector(onCompactFilters),
|
||||||
onBlockHeadersReceived = Vector(onHeaders))
|
onBlockHeadersReceived = Vector(onHeaders)
|
||||||
|
)
|
||||||
|
|
||||||
val streamManager = NodeCallbackStreamManager(callbacks)
|
val streamManager = NodeCallbackStreamManager(callbacks)
|
||||||
Future.successful(streamManager)
|
Future.successful(streamManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
def createBitcoindNodeCallbacksForWallet(wallet: DLCNeutrinoHDWalletApi)(
|
def createBitcoindNodeCallbacksForWallet(
|
||||||
implicit system: ActorSystem): Future[NodeCallbackStreamManager] = {
|
wallet: DLCNeutrinoHDWalletApi
|
||||||
|
)(implicit system: ActorSystem): Future[NodeCallbackStreamManager] = {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
val txSink = Sink.foreachAsync[Transaction](1) { case tx: Transaction =>
|
val txSink = Sink.foreachAsync[Transaction](1) { case tx: Transaction =>
|
||||||
logger.debug(s"Receiving transaction txid=${tx.txIdBE.hex} as a callback")
|
logger.debug(s"Receiving transaction txid=${tx.txIdBE.hex} as a callback")
|
||||||
|
@ -12,8 +12,8 @@ object ChainUtil {
|
|||||||
|
|
||||||
def getBlockHeaderResult(
|
def getBlockHeaderResult(
|
||||||
hashes: Vector[DoubleSha256DigestBE],
|
hashes: Vector[DoubleSha256DigestBE],
|
||||||
chain: ChainApi)(implicit
|
chain: ChainApi
|
||||||
ec: ExecutionContext): Future[Vector[GetBlockHeaderResult]] = {
|
)(implicit ec: ExecutionContext): Future[Vector[GetBlockHeaderResult]] = {
|
||||||
val headersF: Future[Vector[Option[BlockHeaderDb]]] =
|
val headersF: Future[Vector[Option[BlockHeaderDb]]] =
|
||||||
chain.getHeaders(hashes)
|
chain.getHeaders(hashes)
|
||||||
val bestHeightF = chain.getBestBlockHeader().map(_.height)
|
val bestHeightF = chain.getBestBlockHeader().map(_.height)
|
||||||
@ -30,7 +30,8 @@ object ChainUtil {
|
|||||||
headersWithConfs.map {
|
headersWithConfs.map {
|
||||||
case None =>
|
case None =>
|
||||||
sys.error(
|
sys.error(
|
||||||
s"Could not find block header or confirmations for the header ")
|
s"Could not find block header or confirmations for the header "
|
||||||
|
)
|
||||||
case Some((header, confs)) =>
|
case Some((header, confs)) =>
|
||||||
val chainworkStr = {
|
val chainworkStr = {
|
||||||
val bytes = ByteVector(header.chainWork.toByteArray)
|
val bytes = ByteVector(header.chainWork.toByteArray)
|
||||||
|
@ -15,12 +15,12 @@ sealed trait WalletHolderWithLoaderApi {
|
|||||||
|
|
||||||
case class WalletHolderWithNeutrinoLoaderApi(
|
case class WalletHolderWithNeutrinoLoaderApi(
|
||||||
walletHolder: WalletHolder,
|
walletHolder: WalletHolder,
|
||||||
loaderApi: DLCWalletNeutrinoBackendLoader)
|
loaderApi: DLCWalletNeutrinoBackendLoader
|
||||||
extends WalletHolderWithLoaderApi
|
) extends WalletHolderWithLoaderApi
|
||||||
|
|
||||||
case class WalletHolderWithBitcoindLoaderApi(
|
case class WalletHolderWithBitcoindLoaderApi(
|
||||||
walletHolder: WalletHolder,
|
walletHolder: WalletHolder,
|
||||||
loaderApi: DLCWalletBitcoindBackendLoader)
|
loaderApi: DLCWalletBitcoindBackendLoader
|
||||||
extends WalletHolderWithLoaderApi {
|
) extends WalletHolderWithLoaderApi {
|
||||||
val bitcoind: BitcoindRpcClient = loaderApi.bitcoind
|
val bitcoind: BitcoindRpcClient = loaderApi.bitcoind
|
||||||
}
|
}
|
||||||
|
@ -69,8 +69,8 @@ object WebsocketUtil extends BitcoinSLogger {
|
|||||||
|
|
||||||
private def sendHeadersToWs(
|
private def sendHeadersToWs(
|
||||||
notifications: Vector[ChainNotification[_]],
|
notifications: Vector[ChainNotification[_]],
|
||||||
queue: SourceQueueWithComplete[WsNotification[_]])(implicit
|
queue: SourceQueueWithComplete[WsNotification[_]]
|
||||||
ec: ExecutionContext): Future[Unit] = {
|
)(implicit ec: ExecutionContext): Future[Unit] = {
|
||||||
for {
|
for {
|
||||||
_ <- FutureUtil.sequentially(notifications) { case msg =>
|
_ <- FutureUtil.sequentially(notifications) { case msg =>
|
||||||
val x: Future[Unit] = queue
|
val x: Future[Unit] = queue
|
||||||
@ -83,9 +83,11 @@ object WebsocketUtil extends BitcoinSLogger {
|
|||||||
|
|
||||||
def buildChainCallbacks(
|
def buildChainCallbacks(
|
||||||
queue: SourceQueueWithComplete[WsNotification[_]],
|
queue: SourceQueueWithComplete[WsNotification[_]],
|
||||||
chainApi: ChainApi)(implicit
|
chainApi: ChainApi
|
||||||
|
)(implicit
|
||||||
ec: ExecutionContext,
|
ec: ExecutionContext,
|
||||||
chainAppConfig: ChainAppConfig): ChainCallbacks = {
|
chainAppConfig: ChainAppConfig
|
||||||
|
): ChainCallbacks = {
|
||||||
val onBlockProcessed: OnBlockHeaderConnected = {
|
val onBlockProcessed: OnBlockHeaderConnected = {
|
||||||
case headersWithHeight: Vector[(Int, BlockHeader)] =>
|
case headersWithHeight: Vector[(Int, BlockHeader)] =>
|
||||||
val hashes: Vector[DoubleSha256DigestBE] =
|
val hashes: Vector[DoubleSha256DigestBE] =
|
||||||
@ -98,7 +100,7 @@ object WebsocketUtil extends BitcoinSLogger {
|
|||||||
chainAppConfig.ibdBlockProcessedEvents
|
chainAppConfig.ibdBlockProcessedEvents
|
||||||
isIBDF.flatMap { isIBD =>
|
isIBDF.flatMap { isIBD =>
|
||||||
if (isIBD && !emitBlockProccessedWhileIBDOnGoing) {
|
if (isIBD && !emitBlockProccessedWhileIBDOnGoing) {
|
||||||
//only emit the last header so that we don't overwhelm the UI
|
// only emit the last header so that we don't overwhelm the UI
|
||||||
for {
|
for {
|
||||||
results <- resultsF
|
results <- resultsF
|
||||||
notification = BlockProcessedNotification(results.last)
|
notification = BlockProcessedNotification(results.last)
|
||||||
@ -166,15 +168,16 @@ object WebsocketUtil extends BitcoinSLogger {
|
|||||||
ChainCallbacks.onBlockHeaderConnected(onBlockProcessed) +
|
ChainCallbacks.onBlockHeaderConnected(onBlockProcessed) +
|
||||||
ChainCallbacks.onOnSyncFlagChanged(onSyncFlagChanged) +
|
ChainCallbacks.onOnSyncFlagChanged(onSyncFlagChanged) +
|
||||||
ChainCallbacks.onCompactFilterHeaderConnected(
|
ChainCallbacks.onCompactFilterHeaderConnected(
|
||||||
onCompactFilterHeaderProcessed) +
|
onCompactFilterHeaderProcessed
|
||||||
|
) +
|
||||||
ChainCallbacks.onCompactFilterConnected(onCompactFilterProcessed)
|
ChainCallbacks.onCompactFilterConnected(onCompactFilterProcessed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Builds websocket callbacks for the wallet */
|
/** Builds websocket callbacks for the wallet */
|
||||||
def buildWalletCallbacks(
|
def buildWalletCallbacks(
|
||||||
walletQueue: SourceQueueWithComplete[WsNotification[_]],
|
walletQueue: SourceQueueWithComplete[WsNotification[_]],
|
||||||
walletName: String)(implicit
|
walletName: String
|
||||||
system: ActorSystem): WalletCallbackStreamManager = {
|
)(implicit system: ActorSystem): WalletCallbackStreamManager = {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
val onAddressCreated: OnNewAddressGenerated = { addr =>
|
val onAddressCreated: OnNewAddressGenerated = { addr =>
|
||||||
val notification = WalletNotification.NewAddressNotification(addr)
|
val notification = WalletNotification.NewAddressNotification(addr)
|
||||||
@ -183,15 +186,19 @@ object WebsocketUtil extends BitcoinSLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val onTxProcessed: OnTransactionProcessed = { tx =>
|
val onTxProcessed: OnTransactionProcessed = { tx =>
|
||||||
buildTxNotification(wsType = WalletWsType.TxProcessed,
|
buildTxNotification(
|
||||||
tx = tx,
|
wsType = WalletWsType.TxProcessed,
|
||||||
walletQueue = walletQueue)
|
tx = tx,
|
||||||
|
walletQueue = walletQueue
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val onTxBroadcast: OnTransactionBroadcast = { tx =>
|
val onTxBroadcast: OnTransactionBroadcast = { tx =>
|
||||||
buildTxNotification(wsType = WalletWsType.TxBroadcast,
|
buildTxNotification(
|
||||||
tx = tx,
|
wsType = WalletWsType.TxBroadcast,
|
||||||
walletQueue = walletQueue)
|
tx = tx,
|
||||||
|
walletQueue = walletQueue
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val onReservedUtxo: OnReservedUtxos = { utxos =>
|
val onReservedUtxo: OnReservedUtxos = { utxos =>
|
||||||
@ -226,8 +233,9 @@ object WebsocketUtil extends BitcoinSLogger {
|
|||||||
WalletCallbackStreamManager(callbacks = callbacks)
|
WalletCallbackStreamManager(callbacks = callbacks)
|
||||||
}
|
}
|
||||||
|
|
||||||
def buildTorCallbacks(queue: SourceQueueWithComplete[WsNotification[_]])(
|
def buildTorCallbacks(
|
||||||
implicit ec: ExecutionContext): TorCallbacks = {
|
queue: SourceQueueWithComplete[WsNotification[_]]
|
||||||
|
)(implicit ec: ExecutionContext): TorCallbacks = {
|
||||||
val onTorStarted: OnTorStarted = { _ =>
|
val onTorStarted: OnTorStarted = { _ =>
|
||||||
val notification = TorStartedNotification
|
val notification = TorStartedNotification
|
||||||
val offerF = queue.offer(notification)
|
val offerF = queue.offer(notification)
|
||||||
@ -240,8 +248,8 @@ object WebsocketUtil extends BitcoinSLogger {
|
|||||||
private def buildTxNotification(
|
private def buildTxNotification(
|
||||||
wsType: WalletWsType,
|
wsType: WalletWsType,
|
||||||
tx: Transaction,
|
tx: Transaction,
|
||||||
walletQueue: SourceQueueWithComplete[WsNotification[_]])(implicit
|
walletQueue: SourceQueueWithComplete[WsNotification[_]]
|
||||||
ec: ExecutionContext): Future[Unit] = {
|
)(implicit ec: ExecutionContext): Future[Unit] = {
|
||||||
val notification = wsType match {
|
val notification = wsType match {
|
||||||
case WalletWsType.TxProcessed =>
|
case WalletWsType.TxProcessed =>
|
||||||
WalletNotification.TxProcessedNotification(tx)
|
WalletNotification.TxProcessedNotification(tx)
|
||||||
@ -259,8 +267,8 @@ object WebsocketUtil extends BitcoinSLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def buildDLCWalletCallbacks(
|
def buildDLCWalletCallbacks(
|
||||||
walletQueue: SourceQueueWithComplete[WsNotification[_]])(implicit
|
walletQueue: SourceQueueWithComplete[WsNotification[_]]
|
||||||
system: ActorSystem): DLCWalletCallbackStreamManager = {
|
)(implicit system: ActorSystem): DLCWalletCallbackStreamManager = {
|
||||||
import system.dispatcher
|
import system.dispatcher
|
||||||
val onStateChange: OnDLCStateChange = { status: DLCStatus =>
|
val onStateChange: OnDLCStateChange = { status: DLCStatus =>
|
||||||
val notification = WalletNotification.DLCStateChangeNotification(status)
|
val notification = WalletNotification.DLCStateChangeNotification(status)
|
||||||
@ -284,14 +292,15 @@ object WebsocketUtil extends BitcoinSLogger {
|
|||||||
import DLCWalletCallbacks._
|
import DLCWalletCallbacks._
|
||||||
|
|
||||||
val callbacks = onDLCStateChange(onStateChange) + onDLCOfferAdd(
|
val callbacks = onDLCStateChange(onStateChange) + onDLCOfferAdd(
|
||||||
onOfferAdd) + onDLCOfferRemove(onOfferRemove)
|
onOfferAdd
|
||||||
|
) + onDLCOfferRemove(onOfferRemove)
|
||||||
|
|
||||||
DLCWalletCallbackStreamManager(callbacks)
|
DLCWalletCallbackStreamManager(callbacks)
|
||||||
}
|
}
|
||||||
|
|
||||||
def buildDLCNodeCallbacks(
|
def buildDLCNodeCallbacks(
|
||||||
walletQueue: SourceQueueWithComplete[WsNotification[_]])(implicit
|
walletQueue: SourceQueueWithComplete[WsNotification[_]]
|
||||||
ec: ExecutionContext): DLCNodeCallbacks = {
|
)(implicit ec: ExecutionContext): DLCNodeCallbacks = {
|
||||||
|
|
||||||
val onConnectionInitiated: OnPeerConnectionInitiated = { payload =>
|
val onConnectionInitiated: OnPeerConnectionInitiated = { payload =>
|
||||||
val notification =
|
val notification =
|
||||||
|
@ -12,7 +12,8 @@ abstract class AsyncUtil extends AsyncUtilApi {
|
|||||||
|
|
||||||
private def retryRunnable(
|
private def retryRunnable(
|
||||||
condition: => Boolean,
|
condition: => Boolean,
|
||||||
p: Promise[Boolean]): Runnable =
|
p: Promise[Boolean]
|
||||||
|
): Runnable =
|
||||||
new Runnable {
|
new Runnable {
|
||||||
|
|
||||||
override def run(): Unit = {
|
override def run(): Unit = {
|
||||||
@ -24,8 +25,8 @@ abstract class AsyncUtil extends AsyncUtilApi {
|
|||||||
def retryUntilSatisfied(
|
def retryUntilSatisfied(
|
||||||
condition: => Boolean,
|
condition: => Boolean,
|
||||||
interval: FiniteDuration = AsyncUtil.DEFAULT_INTERVAL,
|
interval: FiniteDuration = AsyncUtil.DEFAULT_INTERVAL,
|
||||||
maxTries: Int = DEFAULT_MAX_TRIES)(implicit
|
maxTries: Int = DEFAULT_MAX_TRIES
|
||||||
ec: ExecutionContext): Future[Unit] = {
|
)(implicit ec: ExecutionContext): Future[Unit] = {
|
||||||
val f = () => Future(condition)
|
val f = () => Future(condition)
|
||||||
retryUntilSatisfiedF(f, interval, maxTries)
|
retryUntilSatisfiedF(f, interval, maxTries)
|
||||||
}
|
}
|
||||||
@ -35,32 +36,43 @@ abstract class AsyncUtil extends AsyncUtilApi {
|
|||||||
case object Exponential extends RetryMode
|
case object Exponential extends RetryMode
|
||||||
|
|
||||||
/** The returned Future completes when condition becomes true
|
/** The returned Future completes when condition becomes true
|
||||||
* @param conditionF The condition being waited on
|
* @param conditionF
|
||||||
* @param duration The interval between calls to check condition
|
* The condition being waited on
|
||||||
* @param maxTries If condition is tried this many times, the Future fails
|
* @param duration
|
||||||
* @param system An ActorSystem to schedule calls to condition
|
* The interval between calls to check condition
|
||||||
* @return A Future[Unit] that succeeds if condition becomes true and fails otherwise
|
* @param maxTries
|
||||||
|
* If condition is tried this many times, the Future fails
|
||||||
|
* @param system
|
||||||
|
* An ActorSystem to schedule calls to condition
|
||||||
|
* @return
|
||||||
|
* A Future[Unit] that succeeds if condition becomes true and fails
|
||||||
|
* otherwise
|
||||||
*/
|
*/
|
||||||
def retryUntilSatisfiedF(
|
def retryUntilSatisfiedF(
|
||||||
conditionF: () => Future[Boolean],
|
conditionF: () => Future[Boolean],
|
||||||
interval: FiniteDuration = AsyncUtil.DEFAULT_INTERVAL,
|
interval: FiniteDuration = AsyncUtil.DEFAULT_INTERVAL,
|
||||||
maxTries: Int = DEFAULT_MAX_TRIES,
|
maxTries: Int = DEFAULT_MAX_TRIES,
|
||||||
mode: RetryMode = Linear)(implicit ec: ExecutionContext): Future[Unit] = {
|
mode: RetryMode = Linear
|
||||||
|
)(implicit ec: ExecutionContext): Future[Unit] = {
|
||||||
if (mode == Exponential) {
|
if (mode == Exponential) {
|
||||||
val millis = interval.toMillis
|
val millis = interval.toMillis
|
||||||
if (millis > 0) {
|
if (millis > 0) {
|
||||||
require((millis << maxTries) > 0,
|
require(
|
||||||
s"Too many tries for retryUntilSatisfied(): $maxTries")
|
(millis << maxTries) > 0,
|
||||||
|
s"Too many tries for retryUntilSatisfied(): $maxTries"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val stackTrace: Array[StackTraceElement] =
|
val stackTrace: Array[StackTraceElement] =
|
||||||
Thread.currentThread().getStackTrace
|
Thread.currentThread().getStackTrace
|
||||||
|
|
||||||
retryUntilSatisfiedWithCounter(conditionF = conditionF,
|
retryUntilSatisfiedWithCounter(
|
||||||
interval = interval,
|
conditionF = conditionF,
|
||||||
maxTries = maxTries,
|
interval = interval,
|
||||||
stackTrace = stackTrace,
|
maxTries = maxTries,
|
||||||
mode = mode)
|
stackTrace = stackTrace,
|
||||||
|
mode = mode
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Has a different name so that default values are permitted
|
// Has a different name so that default values are permitted
|
||||||
@ -70,14 +82,18 @@ abstract class AsyncUtil extends AsyncUtilApi {
|
|||||||
counter: Int = 0,
|
counter: Int = 0,
|
||||||
maxTries: Int,
|
maxTries: Int,
|
||||||
stackTrace: Array[StackTraceElement],
|
stackTrace: Array[StackTraceElement],
|
||||||
mode: RetryMode)(implicit ec: ExecutionContext): Future[Unit] = {
|
mode: RetryMode
|
||||||
|
)(implicit ec: ExecutionContext): Future[Unit] = {
|
||||||
conditionF().flatMap { condition =>
|
conditionF().flatMap { condition =>
|
||||||
if (condition) {
|
if (condition) {
|
||||||
Future.unit
|
Future.unit
|
||||||
} else if (counter == maxTries) {
|
} else if (counter == maxTries) {
|
||||||
Future.failed(AsyncUtil.RpcRetryException(
|
Future.failed(
|
||||||
s"Condition timed out after $maxTries attempts with interval=$interval waiting periods",
|
AsyncUtil.RpcRetryException(
|
||||||
stackTrace))
|
s"Condition timed out after $maxTries attempts with interval=$interval waiting periods",
|
||||||
|
stackTrace
|
||||||
|
)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
val p = Promise[Boolean]()
|
val p = Promise[Boolean]()
|
||||||
val runnable = retryRunnable(condition, p)
|
val runnable = retryRunnable(condition, p)
|
||||||
@ -92,32 +108,38 @@ abstract class AsyncUtil extends AsyncUtilApi {
|
|||||||
p.future.flatMap {
|
p.future.flatMap {
|
||||||
case true => Future.unit
|
case true => Future.unit
|
||||||
case false =>
|
case false =>
|
||||||
retryUntilSatisfiedWithCounter(conditionF = conditionF,
|
retryUntilSatisfiedWithCounter(
|
||||||
interval = interval,
|
conditionF = conditionF,
|
||||||
counter = counter + 1,
|
interval = interval,
|
||||||
maxTries = maxTries,
|
counter = counter + 1,
|
||||||
stackTrace = stackTrace,
|
maxTries = maxTries,
|
||||||
mode = mode)
|
stackTrace = stackTrace,
|
||||||
|
mode = mode
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a future that resolved when the condition becomes true, the condition
|
/** Returns a future that resolved when the condition becomes true, the
|
||||||
* is checked maxTries times, or overallTimeout is reached
|
* condition is checked maxTries times, or overallTimeout is reached
|
||||||
* @param condition The blocking condition
|
* @param condition
|
||||||
* @param duration The interval between calls to check condition
|
* The blocking condition
|
||||||
* @param maxTries If condition is tried this many times, an exception is thrown
|
* @param duration
|
||||||
* @param system An ActorSystem to schedule calls to condition
|
* The interval between calls to check condition
|
||||||
|
* @param maxTries
|
||||||
|
* If condition is tried this many times, an exception is thrown
|
||||||
|
* @param system
|
||||||
|
* An ActorSystem to schedule calls to condition
|
||||||
*/
|
*/
|
||||||
def awaitCondition(
|
def awaitCondition(
|
||||||
condition: () => Boolean,
|
condition: () => Boolean,
|
||||||
interval: FiniteDuration = AsyncUtil.DEFAULT_INTERVAL,
|
interval: FiniteDuration = AsyncUtil.DEFAULT_INTERVAL,
|
||||||
maxTries: Int = DEFAULT_MAX_TRIES)(implicit
|
maxTries: Int = DEFAULT_MAX_TRIES
|
||||||
ec: ExecutionContext): Future[Unit] = {
|
)(implicit ec: ExecutionContext): Future[Unit] = {
|
||||||
|
|
||||||
//type hackery here to go from () => Boolean to () => Future[Boolean]
|
// type hackery here to go from () => Boolean to () => Future[Boolean]
|
||||||
//to make sure we re-evaluate every time retryUntilSatisfied is called
|
// to make sure we re-evaluate every time retryUntilSatisfied is called
|
||||||
def conditionDef: Boolean = condition()
|
def conditionDef: Boolean = condition()
|
||||||
val conditionF: () => Future[Boolean] = () => Future(conditionDef)
|
val conditionF: () => Future[Boolean] = () => Future(conditionDef)
|
||||||
|
|
||||||
@ -127,21 +149,25 @@ abstract class AsyncUtil extends AsyncUtilApi {
|
|||||||
def awaitConditionF(
|
def awaitConditionF(
|
||||||
conditionF: () => Future[Boolean],
|
conditionF: () => Future[Boolean],
|
||||||
interval: FiniteDuration = AsyncUtil.DEFAULT_INTERVAL,
|
interval: FiniteDuration = AsyncUtil.DEFAULT_INTERVAL,
|
||||||
maxTries: Int = DEFAULT_MAX_TRIES)(implicit
|
maxTries: Int = DEFAULT_MAX_TRIES
|
||||||
ec: ExecutionContext): Future[Unit] = {
|
)(implicit ec: ExecutionContext): Future[Unit] = {
|
||||||
|
|
||||||
retryUntilSatisfiedF(conditionF = conditionF,
|
retryUntilSatisfiedF(
|
||||||
interval = interval,
|
conditionF = conditionF,
|
||||||
maxTries = maxTries)
|
interval = interval,
|
||||||
|
maxTries = maxTries
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override def nonBlockingSleep(duration: FiniteDuration): Future[Unit] = {
|
override def nonBlockingSleep(duration: FiniteDuration): Future[Unit] = {
|
||||||
val p = Promise[Unit]()
|
val p = Promise[Unit]()
|
||||||
val r: Runnable = () => p.success(())
|
val r: Runnable = () => p.success(())
|
||||||
AsyncUtil.scheduler.scheduleOnce(duration.toMillis,
|
AsyncUtil.scheduler.scheduleOnce(
|
||||||
TimeUnit.MILLISECONDS,
|
duration.toMillis,
|
||||||
r)
|
TimeUnit.MILLISECONDS,
|
||||||
|
r
|
||||||
|
)
|
||||||
p.future
|
p.future
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,8 +176,8 @@ object AsyncUtil extends AsyncUtil {
|
|||||||
|
|
||||||
case class RpcRetryException(
|
case class RpcRetryException(
|
||||||
message: String,
|
message: String,
|
||||||
caller: Array[StackTraceElement])
|
caller: Array[StackTraceElement]
|
||||||
extends Exception(message) {
|
) extends Exception(message) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Someone who calls a method in this class will be interested
|
Someone who calls a method in this class will be interested
|
||||||
@ -161,10 +187,12 @@ object AsyncUtil extends AsyncUtil {
|
|||||||
*
|
*
|
||||||
* This trims the top of the stack trace to exclude these internal calls.
|
* This trims the top of the stack trace to exclude these internal calls.
|
||||||
*/
|
*/
|
||||||
val internalFiles: Vector[String] = Vector("AsyncUtil.scala",
|
val internalFiles: Vector[String] = Vector(
|
||||||
"RpcUtil.scala",
|
"AsyncUtil.scala",
|
||||||
"TestAsyncUtil.scala",
|
"RpcUtil.scala",
|
||||||
"TestRpcUtil.scala")
|
"TestAsyncUtil.scala",
|
||||||
|
"TestRpcUtil.scala"
|
||||||
|
)
|
||||||
|
|
||||||
private val relevantStackTrace =
|
private val relevantStackTrace =
|
||||||
caller.tail.dropWhile(elem => internalFiles.contains(elem.getFileName))
|
caller.tail.dropWhile(elem => internalFiles.contains(elem.getFileName))
|
||||||
@ -182,7 +210,9 @@ object AsyncUtil extends AsyncUtil {
|
|||||||
*/
|
*/
|
||||||
private[bitcoins] val DEFAULT_MAX_TRIES: Int = 50
|
private[bitcoins] val DEFAULT_MAX_TRIES: Int = 50
|
||||||
|
|
||||||
/** Gives you a thread factory with the given prefix with a counter appended to the name */
|
/** Gives you a thread factory with the given prefix with a counter appended
|
||||||
|
* to the name
|
||||||
|
*/
|
||||||
def getNewThreadFactory(prefix: String): ThreadFactory = {
|
def getNewThreadFactory(prefix: String): ThreadFactory = {
|
||||||
new ThreadFactory {
|
new ThreadFactory {
|
||||||
private val atomicInteger = new AtomicInteger(0)
|
private val atomicInteger = new AtomicInteger(0)
|
||||||
|
@ -35,5 +35,5 @@ object BlockBench extends App {
|
|||||||
|
|
||||||
0.until(10).foreach(_ => bench1())
|
0.until(10).foreach(_ => bench1())
|
||||||
|
|
||||||
//bench2()
|
// bench2()
|
||||||
}
|
}
|
||||||
|
@ -13,13 +13,15 @@ import scala.concurrent.Future
|
|||||||
import scala.concurrent.duration.DurationInt
|
import scala.concurrent.duration.DurationInt
|
||||||
import scala.util.{Failure, Success}
|
import scala.util.{Failure, Success}
|
||||||
|
|
||||||
/** This test spins up one test node and [[NetworkSize]] sender nodes, which open channels with the test one.
|
/** This test spins up one test node and [[NetworkSize]] sender nodes, which
|
||||||
* Then each sender node sends [[PaymentCount]] payments to the test node one by one. For each payment the
|
* open channels with the test one. Then each sender node sends
|
||||||
* test node generates an invoice and the send node pays it using `sendtonode` API call.
|
* [[PaymentCount]] payments to the test node one by one. For each payment the
|
||||||
|
* test node generates an invoice and the send node pays it using `sendtonode`
|
||||||
|
* API call.
|
||||||
*
|
*
|
||||||
* The test keeps track of times when a payment was initiated, when the payment ID was received,
|
* The test keeps track of times when a payment was initiated, when the payment
|
||||||
* and when the corresponding web socket event was received. It writes all results into [[OutputFileName]]
|
* ID was received, and when the corresponding web socket event was received.
|
||||||
* in CSV format.
|
* It writes all results into [[OutputFileName]] in CSV format.
|
||||||
*/
|
*/
|
||||||
object EclairBench extends App with EclairRpcTestUtil {
|
object EclairBench extends App with EclairRpcTestUtil {
|
||||||
|
|
||||||
@ -72,7 +74,8 @@ object EclairBench extends App with EclairRpcTestUtil {
|
|||||||
def sendPayments(
|
def sendPayments(
|
||||||
network: EclairNetwork,
|
network: EclairNetwork,
|
||||||
amount: MilliSatoshis,
|
amount: MilliSatoshis,
|
||||||
count: Int): Future[Vector[PaymentId]] =
|
count: Int
|
||||||
|
): Future[Vector[PaymentId]] =
|
||||||
for {
|
for {
|
||||||
_ <- network.testEclairNode.getInfo
|
_ <- network.testEclairNode.getInfo
|
||||||
paymentIds <- Future.sequence(network.networkEclairNodes.map { node =>
|
paymentIds <- Future.sequence(network.networkEclairNodes.map { node =>
|
||||||
@ -104,22 +107,26 @@ object EclairBench extends App with EclairRpcTestUtil {
|
|||||||
val _ = logEvent(event)
|
val _ = logEvent(event)
|
||||||
}
|
}
|
||||||
_ = println(
|
_ = println(
|
||||||
s"Set up $NetworkSize nodes, that will send $PaymentCount payments to the test node each")
|
s"Set up $NetworkSize nodes, that will send $PaymentCount payments to the test node each"
|
||||||
|
)
|
||||||
_ = println(
|
_ = println(
|
||||||
s"Test node data directory: ${network.testEclairNode.instance.authCredentials.datadir
|
s"Test node data directory: ${network.testEclairNode.instance.authCredentials.datadir
|
||||||
.getOrElse("")}")
|
.getOrElse("")}"
|
||||||
|
)
|
||||||
_ = println("Testing...")
|
_ = println("Testing...")
|
||||||
_ <- sendPayments(network, PaymentAmount, PaymentCount)
|
_ <- sendPayments(network, PaymentAmount, PaymentCount)
|
||||||
_ <- TestAsyncUtil.retryUntilSatisfied(
|
_ <- TestAsyncUtil.retryUntilSatisfied(
|
||||||
condition = paymentLog.size() == NetworkSize * PaymentCount,
|
condition = paymentLog.size() == NetworkSize * PaymentCount,
|
||||||
interval = 1.second,
|
interval = 1.second,
|
||||||
maxTries = 100)
|
maxTries = 100
|
||||||
|
)
|
||||||
_ <-
|
_ <-
|
||||||
TestAsyncUtil
|
TestAsyncUtil
|
||||||
.retryUntilSatisfied(
|
.retryUntilSatisfied(
|
||||||
condition = EclairBenchUtil.paymentLogValues().forall(_.completed),
|
condition = EclairBenchUtil.paymentLogValues().forall(_.completed),
|
||||||
interval = 1.second,
|
interval = 1.second,
|
||||||
maxTries = 100)
|
maxTries = 100
|
||||||
|
)
|
||||||
.recover { case ex: Throwable => ex.printStackTrace() }
|
.recover { case ex: Throwable => ex.printStackTrace() }
|
||||||
_ = println("\nDone!")
|
_ = println("\nDone!")
|
||||||
} yield {
|
} yield {
|
||||||
@ -128,13 +135,15 @@ object EclairBench extends App with EclairRpcTestUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val res: Future[Unit] = for {
|
val res: Future[Unit] = for {
|
||||||
network <- EclairNetwork.start(TestEclairVersion,
|
network <- EclairNetwork.start(
|
||||||
TestEclairCommit,
|
TestEclairVersion,
|
||||||
SenderEclairVersion,
|
TestEclairCommit,
|
||||||
SenderEclairCommit,
|
SenderEclairVersion,
|
||||||
NetworkSize,
|
SenderEclairCommit,
|
||||||
ChannelAmount,
|
NetworkSize,
|
||||||
LogbackXml)
|
ChannelAmount,
|
||||||
|
LogbackXml
|
||||||
|
)
|
||||||
log <- runTests(network).recoverWith { case e: Throwable =>
|
log <- runTests(network).recoverWith { case e: Throwable =>
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
Future.successful(Vector.empty[PaymentLogEntry])
|
Future.successful(Vector.empty[PaymentLogEntry])
|
||||||
@ -145,17 +154,20 @@ object EclairBench extends App with EclairRpcTestUtil {
|
|||||||
val first = log.head
|
val first = log.head
|
||||||
val csv =
|
val csv =
|
||||||
Vector(
|
Vector(
|
||||||
"time,number_of_payments,payment_hash,payment_id,event,payment_sent_at,payment_id_received_at,event_received_at,received_in,completed_in") ++
|
"time,number_of_payments,payment_hash,payment_id,event,payment_sent_at,payment_id_received_at,event_received_at,received_in,completed_in"
|
||||||
|
) ++
|
||||||
log.zipWithIndex
|
log.zipWithIndex
|
||||||
.map { case (x, i) =>
|
.map { case (x, i) =>
|
||||||
s"${x.paymentSentAt - first.paymentSentAt},${i + 1},${x.toCSV}"
|
s"${x.paymentSentAt - first.paymentSentAt},${i + 1},${x.toCSV}"
|
||||||
}
|
}
|
||||||
val outputFile = new File(OutputFileName)
|
val outputFile = new File(OutputFileName)
|
||||||
Files.write(outputFile.toPath,
|
Files.write(
|
||||||
EclairBenchUtil.convertStrings(csv),
|
outputFile.toPath,
|
||||||
StandardOpenOption.CREATE,
|
EclairBenchUtil.convertStrings(csv),
|
||||||
StandardOpenOption.WRITE,
|
StandardOpenOption.CREATE,
|
||||||
StandardOpenOption.TRUNCATE_EXISTING)
|
StandardOpenOption.WRITE,
|
||||||
|
StandardOpenOption.TRUNCATE_EXISTING
|
||||||
|
)
|
||||||
println(s"The test results was written in ${outputFile.getAbsolutePath}")
|
println(s"The test results was written in ${outputFile.getAbsolutePath}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,14 @@ object PaymentLog {
|
|||||||
event: Option[WebSocketEvent] = None,
|
event: Option[WebSocketEvent] = None,
|
||||||
paymentSentAt: Long,
|
paymentSentAt: Long,
|
||||||
paymentIdReceivedAt: Long = 0,
|
paymentIdReceivedAt: Long = 0,
|
||||||
eventReceivedAt: Long = 0) {
|
eventReceivedAt: Long = 0
|
||||||
|
) {
|
||||||
|
|
||||||
def withPaymentHash(paymentHash: Sha256Digest): PaymentLogEntry =
|
def withPaymentHash(paymentHash: Sha256Digest): PaymentLogEntry =
|
||||||
copy(paymentHash = Some(paymentHash),
|
copy(
|
||||||
paymentSentAt = System.currentTimeMillis())
|
paymentHash = Some(paymentHash),
|
||||||
|
paymentSentAt = System.currentTimeMillis()
|
||||||
|
)
|
||||||
|
|
||||||
def withPaymentId(id: PaymentId): PaymentLogEntry =
|
def withPaymentId(id: PaymentId): PaymentLogEntry =
|
||||||
copy(id = Some(id), paymentIdReceivedAt = System.currentTimeMillis())
|
copy(id = Some(id), paymentIdReceivedAt = System.currentTimeMillis())
|
||||||
@ -47,7 +50,8 @@ object PaymentLog {
|
|||||||
part.timestamp.toEpochMilli
|
part.timestamp.toEpochMilli
|
||||||
case None =>
|
case None =>
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
s"PaymentReceived but with no parts, got $e")
|
s"PaymentReceived but with no parts, got $e"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
case PaymentFailed(_, _, _, timestamp) => timestamp.toEpochMilli
|
case PaymentFailed(_, _, _, timestamp) => timestamp.toEpochMilli
|
||||||
case _: WebSocketEvent =>
|
case _: WebSocketEvent =>
|
||||||
@ -57,18 +61,21 @@ object PaymentLog {
|
|||||||
|
|
||||||
def toCSV: String =
|
def toCSV: String =
|
||||||
s"""${paymentHash
|
s"""${paymentHash
|
||||||
.map(_.hex)
|
.map(_.hex)
|
||||||
.getOrElse("")},${id.map(_.toString).getOrElse("")},${event
|
.getOrElse("")},${id.map(_.toString).getOrElse("")},${event
|
||||||
.map(_.getClass.getName.split('$').last)
|
.map(_.getClass.getName.split('$').last)
|
||||||
.getOrElse(
|
.getOrElse(
|
||||||
"")},$paymentSentAt,$paymentIdReceivedAt,$eventReceivedAt,${paymentIdReceivedAt - paymentSentAt},${eventReceivedAt - paymentIdReceivedAt}"""
|
""
|
||||||
|
)},$paymentSentAt,$paymentIdReceivedAt,$eventReceivedAt,${paymentIdReceivedAt - paymentSentAt},${eventReceivedAt - paymentIdReceivedAt}"""
|
||||||
}
|
}
|
||||||
|
|
||||||
object PaymentLogEntry {
|
object PaymentLogEntry {
|
||||||
|
|
||||||
def apply(paymentHash: Sha256Digest): PaymentLogEntry = {
|
def apply(paymentHash: Sha256Digest): PaymentLogEntry = {
|
||||||
PaymentLogEntry(paymentSentAt = System.currentTimeMillis(),
|
PaymentLogEntry(
|
||||||
paymentHash = Some(paymentHash))
|
paymentSentAt = System.currentTimeMillis(),
|
||||||
|
paymentHash = Some(paymentHash)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,13 +94,15 @@ object PaymentLog {
|
|||||||
|
|
||||||
def logPaymentId(
|
def logPaymentId(
|
||||||
paymentHash: Sha256Digest,
|
paymentHash: Sha256Digest,
|
||||||
paymentId: PaymentId): PaymentLogEntry = {
|
paymentId: PaymentId
|
||||||
|
): PaymentLogEntry = {
|
||||||
paymentLog.compute(
|
paymentLog.compute(
|
||||||
paymentHash,
|
paymentHash,
|
||||||
new BiFunction[Sha256Digest, PaymentLogEntry, PaymentLogEntry] {
|
new BiFunction[Sha256Digest, PaymentLogEntry, PaymentLogEntry] {
|
||||||
override def apply(
|
override def apply(
|
||||||
hash: Sha256Digest,
|
hash: Sha256Digest,
|
||||||
old: PaymentLogEntry): PaymentLogEntry = {
|
old: PaymentLogEntry
|
||||||
|
): PaymentLogEntry = {
|
||||||
val log = if (old == null) {
|
val log = if (old == null) {
|
||||||
PaymentLogEntry(paymentSentAt = 0, paymentHash = Some(hash))
|
PaymentLogEntry(paymentSentAt = 0, paymentHash = Some(hash))
|
||||||
} else {
|
} else {
|
||||||
@ -121,7 +130,8 @@ object PaymentLog {
|
|||||||
new BiFunction[Sha256Digest, PaymentLogEntry, PaymentLogEntry] {
|
new BiFunction[Sha256Digest, PaymentLogEntry, PaymentLogEntry] {
|
||||||
override def apply(
|
override def apply(
|
||||||
hash: Sha256Digest,
|
hash: Sha256Digest,
|
||||||
old: PaymentLogEntry): PaymentLogEntry = {
|
old: PaymentLogEntry
|
||||||
|
): PaymentLogEntry = {
|
||||||
val log = if (old == null) {
|
val log = if (old == null) {
|
||||||
PaymentLogEntry(paymentSentAt = 0, paymentHash = Some(hash))
|
PaymentLogEntry(paymentSentAt = 0, paymentHash = Some(hash))
|
||||||
} else {
|
} else {
|
||||||
@ -136,7 +146,8 @@ object PaymentLog {
|
|||||||
new BiFunction[Sha256Digest, Promise[Unit], Promise[Unit]] {
|
new BiFunction[Sha256Digest, Promise[Unit], Promise[Unit]] {
|
||||||
override def apply(
|
override def apply(
|
||||||
hash: Sha256Digest,
|
hash: Sha256Digest,
|
||||||
old: Promise[Unit]): Promise[Unit] = {
|
old: Promise[Unit]
|
||||||
|
): Promise[Unit] = {
|
||||||
val promise = if (old == null) {
|
val promise = if (old == null) {
|
||||||
Promise[Unit]()
|
Promise[Unit]()
|
||||||
} else {
|
} else {
|
||||||
|
@ -39,8 +39,8 @@ class BitcoindInstanceTest extends BitcoindRpcTest {
|
|||||||
pw.close()
|
pw.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tests that the client can call the isStartedF method
|
/** Tests that the client can call the isStartedF method without throwing and
|
||||||
* without throwing and then start
|
* then start
|
||||||
*/
|
*/
|
||||||
private def testClientStart(client: BitcoindRpcClient): Future[Assertion] =
|
private def testClientStart(client: BitcoindRpcClient): Future[Assertion] =
|
||||||
synchronized {
|
synchronized {
|
||||||
@ -71,7 +71,8 @@ class BitcoindInstanceTest extends BitcoindRpcTest {
|
|||||||
val instance = BitcoindInstanceLocal.fromConfig(conf, newestBitcoindBinary)
|
val instance = BitcoindInstanceLocal.fromConfig(conf, newestBitcoindBinary)
|
||||||
assert(
|
assert(
|
||||||
instance.authCredentials
|
instance.authCredentials
|
||||||
.isInstanceOf[BitcoindAuthCredentials.CookieBased])
|
.isInstanceOf[BitcoindAuthCredentials.CookieBased]
|
||||||
|
)
|
||||||
|
|
||||||
val cli = BitcoindRpcClient.withActorSystem(instance)
|
val cli = BitcoindRpcClient.withActorSystem(instance)
|
||||||
testClientStart(cli)
|
testClientStart(cli)
|
||||||
@ -91,7 +92,8 @@ class BitcoindInstanceTest extends BitcoindRpcTest {
|
|||||||
val instance = BitcoindInstanceLocal.fromConfig(conf, newestBitcoindBinary)
|
val instance = BitcoindInstanceLocal.fromConfig(conf, newestBitcoindBinary)
|
||||||
assert(
|
assert(
|
||||||
instance.authCredentials
|
instance.authCredentials
|
||||||
.isInstanceOf[BitcoindAuthCredentials.PasswordBased])
|
.isInstanceOf[BitcoindAuthCredentials.PasswordBased]
|
||||||
|
)
|
||||||
testClientStart(BitcoindRpcClient.withActorSystem(instance))
|
testClientStart(BitcoindRpcClient.withActorSystem(instance))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,8 +118,10 @@ class BitcoindInstanceTest extends BitcoindRpcTest {
|
|||||||
|
|
||||||
val conf = BitcoindConfig(confStr, FileUtil.tmpDir())
|
val conf = BitcoindConfig(confStr, FileUtil.tmpDir())
|
||||||
val authCredentials =
|
val authCredentials =
|
||||||
BitcoindAuthCredentials.PasswordBased(username = "bitcoin-s",
|
BitcoindAuthCredentials.PasswordBased(
|
||||||
password = "strong_password")
|
username = "bitcoin-s",
|
||||||
|
password = "strong_password"
|
||||||
|
)
|
||||||
val instance =
|
val instance =
|
||||||
BitcoindInstanceLocal(
|
BitcoindInstanceLocal(
|
||||||
network = RegTest,
|
network = RegTest,
|
||||||
@ -167,8 +171,10 @@ class BitcoindInstanceTest extends BitcoindRpcTest {
|
|||||||
|
|
||||||
val conf = BitcoindConfig(confStr, FileUtil.tmpDir())
|
val conf = BitcoindConfig(confStr, FileUtil.tmpDir())
|
||||||
val authCredentials =
|
val authCredentials =
|
||||||
BitcoindAuthCredentials.PasswordBased(username = "bitcoin-s",
|
BitcoindAuthCredentials.PasswordBased(
|
||||||
password = "strong_password")
|
username = "bitcoin-s",
|
||||||
|
password = "strong_password"
|
||||||
|
)
|
||||||
val instance =
|
val instance =
|
||||||
BitcoindInstanceLocal(
|
BitcoindInstanceLocal(
|
||||||
network = RegTest,
|
network = RegTest,
|
||||||
|
@ -35,7 +35,8 @@ class TestRpcUtilTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
assert(dir.isDirectory)
|
assert(dir.isDirectory)
|
||||||
assert(dir.getPath().startsWith(scala.util.Properties.tmpDir))
|
assert(dir.getPath().startsWith(scala.util.Properties.tmpDir))
|
||||||
assert(
|
assert(
|
||||||
dir.listFiles.contains(new File(dir.getAbsolutePath + "/bitcoin.conf")))
|
dir.listFiles.contains(new File(dir.getAbsolutePath + "/bitcoin.conf"))
|
||||||
|
)
|
||||||
FileUtil.deleteTmpDir(dir)
|
FileUtil.deleteTmpDir(dir)
|
||||||
assert(!dir.exists)
|
assert(!dir.exists)
|
||||||
}
|
}
|
||||||
@ -63,15 +64,18 @@ class TestRpcUtilTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
val allClients = nodes.toVector
|
val allClients = nodes.toVector
|
||||||
for {
|
for {
|
||||||
heightPreGeneration <- first.getBlockCount()
|
heightPreGeneration <- first.getBlockCount()
|
||||||
_ <- BitcoindRpcTestUtil.generateAllAndSync(allClients,
|
_ <- BitcoindRpcTestUtil.generateAllAndSync(
|
||||||
blocks = blocksToGenerate)
|
allClients,
|
||||||
|
blocks = blocksToGenerate
|
||||||
|
)
|
||||||
firstHash <- first.getBestBlockHash()
|
firstHash <- first.getBestBlockHash()
|
||||||
secondHash <- second.getBestBlockHash()
|
secondHash <- second.getBestBlockHash()
|
||||||
heightPostGeneration <- first.getBlockCount()
|
heightPostGeneration <- first.getBlockCount()
|
||||||
} yield {
|
} yield {
|
||||||
assert(firstHash == secondHash)
|
assert(firstHash == secondHash)
|
||||||
assert(
|
assert(
|
||||||
heightPostGeneration - heightPreGeneration == blocksToGenerate * allClients.length)
|
heightPostGeneration - heightPreGeneration == blocksToGenerate * allClients.length
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,10 +86,12 @@ class TestRpcUtilTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
address <- second.getNewAddress
|
address <- second.getNewAddress
|
||||||
txid <- first.sendToAddress(address, Bitcoins.one)
|
txid <- first.sendToAddress(address, Bitcoins.one)
|
||||||
hashes <- BitcoindRpcTestUtil.generateAndSync(Vector(first, second))
|
hashes <- BitcoindRpcTestUtil.generateAndSync(Vector(first, second))
|
||||||
vout <- BitcoindRpcTestUtil.findOutput(first,
|
vout <- BitcoindRpcTestUtil.findOutput(
|
||||||
txid,
|
first,
|
||||||
Bitcoins.one,
|
txid,
|
||||||
Some(hashes.head))
|
Bitcoins.one,
|
||||||
|
Some(hashes.head)
|
||||||
|
)
|
||||||
tx <- first.getRawTransaction(txid, Some(hashes.head))
|
tx <- first.getRawTransaction(txid, Some(hashes.head))
|
||||||
} yield {
|
} yield {
|
||||||
assert(tx.vout(vout.toInt).value == Bitcoins.one)
|
assert(tx.vout(vout.toInt).value == Bitcoins.one)
|
||||||
|
@ -230,10 +230,13 @@ class BlockchainRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
txs <- Future.sequence(
|
txs <- Future.sequence(
|
||||||
block.transactions
|
block.transactions
|
||||||
.filterNot(_.isCoinbase)
|
.filterNot(_.isCoinbase)
|
||||||
.map(tx => client.getTransaction(tx.txIdBE)))
|
.map(tx => client.getTransaction(tx.txIdBE))
|
||||||
|
)
|
||||||
|
|
||||||
prevFilter <- client.getBlockFilter(block.blockHeader.previousBlockHashBE,
|
prevFilter <- client.getBlockFilter(
|
||||||
FilterType.Basic)
|
block.blockHeader.previousBlockHashBE,
|
||||||
|
FilterType.Basic
|
||||||
|
)
|
||||||
} yield {
|
} yield {
|
||||||
val pubKeys = txs.flatMap(_.hex.outputs.map(_.scriptPubKey)).toVector
|
val pubKeys = txs.flatMap(_.hex.outputs.map(_.scriptPubKey)).toVector
|
||||||
val filter = BlockFilter(block, pubKeys)
|
val filter = BlockFilter(block, pubKeys)
|
||||||
@ -242,7 +245,8 @@ class BlockchainRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
blockFilter.header == filter
|
blockFilter.header == filter
|
||||||
.getHeader(prevFilter.header.flip)
|
.getHeader(prevFilter.header.flip)
|
||||||
.hash
|
.hash
|
||||||
.flip)
|
.flip
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,17 +132,21 @@ class MempoolRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
for {
|
for {
|
||||||
_ <- client.generate(1)
|
_ <- client.generate(1)
|
||||||
address1 <- client.getNewAddress
|
address1 <- client.getNewAddress
|
||||||
txid1 <- BitcoindRpcTestUtil.fundMemPoolTransaction(client,
|
txid1 <- BitcoindRpcTestUtil.fundMemPoolTransaction(
|
||||||
address1,
|
client,
|
||||||
Bitcoins(2))
|
address1,
|
||||||
|
Bitcoins(2)
|
||||||
|
)
|
||||||
mempool <- client.getRawMemPool
|
mempool <- client.getRawMemPool
|
||||||
address2 <- client.getNewAddress
|
address2 <- client.getNewAddress
|
||||||
|
|
||||||
createdTx <- {
|
createdTx <- {
|
||||||
val input: TransactionInput =
|
val input: TransactionInput =
|
||||||
TransactionInput(TransactionOutPoint(txid1.flip, UInt32.zero),
|
TransactionInput(
|
||||||
ScriptSignature.empty,
|
TransactionOutPoint(txid1.flip, UInt32.zero),
|
||||||
UInt32.max - UInt32.one)
|
ScriptSignature.empty,
|
||||||
|
UInt32.max - UInt32.one
|
||||||
|
)
|
||||||
client
|
client
|
||||||
.createRawTransaction(Vector(input), Map(address2 -> Bitcoins.one))
|
.createRawTransaction(Vector(input), Map(address2 -> Bitcoins.one))
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,10 @@ class MessageRpcTest extends BitcoindRpcTest {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
client <- clientF
|
client <- clientF
|
||||||
signature <- client.signMessageWithPrivKey(privKey.toPrivateKeyBytes(),
|
signature <- client.signMessageWithPrivKey(
|
||||||
message)
|
privKey.toPrivateKeyBytes(),
|
||||||
|
message
|
||||||
|
)
|
||||||
validity <- client.verifyMessage(address, signature, message)
|
validity <- client.verifyMessage(address, signature, message)
|
||||||
} yield assert(validity)
|
} yield assert(validity)
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,15 @@ class MiningRpcTest extends BitcoindRpcTest {
|
|||||||
TransactionInput(
|
TransactionInput(
|
||||||
TransactionOutPoint(output.txid.flip, UInt32(output.vout)),
|
TransactionOutPoint(output.txid.flip, UInt32(output.vout)),
|
||||||
ScriptSignature.empty,
|
ScriptSignature.empty,
|
||||||
UInt32.max - UInt32(2))
|
UInt32.max - UInt32(2)
|
||||||
|
)
|
||||||
val inputs = Vector(input)
|
val inputs = Vector(input)
|
||||||
|
|
||||||
val outputs =
|
val outputs =
|
||||||
Map(address -> Bitcoins(0.5),
|
Map(
|
||||||
changeAddress -> Bitcoins(output.amount.toBigDecimal - 0.55))
|
address -> Bitcoins(0.5),
|
||||||
|
changeAddress -> Bitcoins(output.amount.toBigDecimal - 0.55)
|
||||||
|
)
|
||||||
|
|
||||||
client.createRawTransaction(inputs, outputs)
|
client.createRawTransaction(inputs, outputs)
|
||||||
}
|
}
|
||||||
@ -97,7 +100,9 @@ class MiningRpcTest extends BitcoindRpcTest {
|
|||||||
foundBlocks.foreach { case found: GetBlockWithTransactionsResultV22 =>
|
foundBlocks.foreach { case found: GetBlockWithTransactionsResultV22 =>
|
||||||
assert(
|
assert(
|
||||||
found.tx.exists(
|
found.tx.exists(
|
||||||
_.vout.exists(_.scriptPubKey.address == Some(address))))
|
_.vout.exists(_.scriptPubKey.address == Some(address))
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
succeed
|
succeed
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,9 @@ import java.io.File
|
|||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
import scala.concurrent.duration.DurationInt
|
import scala.concurrent.duration.DurationInt
|
||||||
|
|
||||||
/** These tests are all copied over from WalletRpcTest and changed to be for multi-wallet */
|
/** These tests are all copied over from WalletRpcTest and changed to be for
|
||||||
|
* multi-wallet
|
||||||
|
*/
|
||||||
class MultiWalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
class MultiWalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
||||||
|
|
||||||
val walletName = "other"
|
val walletName = "other"
|
||||||
@ -43,9 +45,12 @@ class MultiWalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
clientsF.flatMap(setupWalletClient)
|
clientsF.flatMap(setupWalletClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** We need to test bitcoin core's wallet specific features, so we need to set that up */
|
/** We need to test bitcoin core's wallet specific features, so we need to set
|
||||||
private def setupWalletClient(pair: NodePair[BitcoindRpcClient]): Future[
|
* that up
|
||||||
NodePair[BitcoindRpcClient]] = {
|
*/
|
||||||
|
private def setupWalletClient(
|
||||||
|
pair: NodePair[BitcoindRpcClient]
|
||||||
|
): Future[NodePair[BitcoindRpcClient]] = {
|
||||||
val NodePair(client: BitcoindRpcClient, walletClient: BitcoindRpcClient) =
|
val NodePair(client: BitcoindRpcClient, walletClient: BitcoindRpcClient) =
|
||||||
pair
|
pair
|
||||||
for {
|
for {
|
||||||
@ -228,9 +233,11 @@ class MultiWalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
for {
|
for {
|
||||||
address <- otherClient.getNewAddress(Some(walletName))
|
address <- otherClient.getNewAddress(Some(walletName))
|
||||||
_ <- client.walletPassphrase(password, 1000, Some(walletName))
|
_ <- client.walletPassphrase(password, 1000, Some(walletName))
|
||||||
txid <- client.sendToAddress(address,
|
txid <- client.sendToAddress(
|
||||||
Bitcoins(1),
|
address,
|
||||||
walletNameOpt = Some(walletName))
|
Bitcoins(1),
|
||||||
|
walletNameOpt = Some(walletName)
|
||||||
|
)
|
||||||
transaction <-
|
transaction <-
|
||||||
client.getTransaction(txid, walletNameOpt = Some(walletName))
|
client.getTransaction(txid, walletNameOpt = Some(walletName))
|
||||||
} yield {
|
} yield {
|
||||||
@ -248,8 +255,10 @@ class MultiWalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
_ <- client.walletPassphrase(password, 1000, Some(walletName))
|
_ <- client.walletPassphrase(password, 1000, Some(walletName))
|
||||||
txid <-
|
txid <-
|
||||||
client
|
client
|
||||||
.sendMany(Map(address1 -> Bitcoins(1), address2 -> Bitcoins(2)),
|
.sendMany(
|
||||||
walletNameOpt = Some(walletName))
|
Map(address1 -> Bitcoins(1), address2 -> Bitcoins(2)),
|
||||||
|
walletNameOpt = Some(walletName)
|
||||||
|
)
|
||||||
transaction <-
|
transaction <-
|
||||||
client.getTransaction(txid, walletNameOpt = Some(walletName))
|
client.getTransaction(txid, walletNameOpt = Some(walletName))
|
||||||
} yield {
|
} yield {
|
||||||
@ -286,20 +295,27 @@ class MultiWalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
for {
|
for {
|
||||||
firstResult <-
|
firstResult <-
|
||||||
client
|
client
|
||||||
.createMultiSig(2,
|
.createMultiSig(
|
||||||
Vector(privKey1.publicKey, privKey2.publicKey),
|
2,
|
||||||
AddressType.Bech32,
|
Vector(privKey1.publicKey, privKey2.publicKey),
|
||||||
walletNameOpt = Some(walletName))
|
AddressType.Bech32,
|
||||||
|
walletNameOpt = Some(walletName)
|
||||||
|
)
|
||||||
address2 = firstResult.address
|
address2 = firstResult.address
|
||||||
|
|
||||||
secondResult <-
|
secondResult <-
|
||||||
client
|
client
|
||||||
.importMulti(
|
.importMulti(
|
||||||
Vector(
|
Vector(
|
||||||
RpcOpts.ImportMultiRequest(RpcOpts.ImportMultiAddress(address1),
|
RpcOpts.ImportMultiRequest(
|
||||||
UInt32(0)),
|
RpcOpts.ImportMultiAddress(address1),
|
||||||
RpcOpts.ImportMultiRequest(RpcOpts.ImportMultiAddress(address2),
|
UInt32(0)
|
||||||
UInt32(0))),
|
),
|
||||||
|
RpcOpts.ImportMultiRequest(
|
||||||
|
RpcOpts.ImportMultiAddress(address2),
|
||||||
|
UInt32(0)
|
||||||
|
)
|
||||||
|
),
|
||||||
rescan = false,
|
rescan = false,
|
||||||
walletNameOpt = Some(walletName)
|
walletNameOpt = Some(walletName)
|
||||||
)
|
)
|
||||||
@ -343,7 +359,9 @@ class MultiWalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
assert(transaction.inputs.length == 1)
|
assert(transaction.inputs.length == 1)
|
||||||
assert(
|
assert(
|
||||||
transaction.outputs.contains(
|
transaction.outputs.contains(
|
||||||
TransactionOutput(Bitcoins(1), address.scriptPubKey)))
|
TransactionOutput(Bitcoins(1), address.scriptPubKey)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,8 +15,10 @@ class MultisigRpcTest extends BitcoindRpcTest {
|
|||||||
BitcoindRpcTestUtil.instance(versionOpt = Some(BitcoindVersion.newest))
|
BitcoindRpcTestUtil.instance(versionOpt = Some(BitcoindVersion.newest))
|
||||||
|
|
||||||
lazy val clientF: Future[BitcoindRpcClient] =
|
lazy val clientF: Future[BitcoindRpcClient] =
|
||||||
BitcoindRpcTestUtil.startedBitcoindRpcClient(instanceOpt = Some(instance),
|
BitcoindRpcTestUtil.startedBitcoindRpcClient(
|
||||||
clientAccum = clientAccum)
|
instanceOpt = Some(instance),
|
||||||
|
clientAccum = clientAccum
|
||||||
|
)
|
||||||
|
|
||||||
behavior of "MultisigRpc"
|
behavior of "MultisigRpc"
|
||||||
|
|
||||||
@ -29,9 +31,11 @@ class MultisigRpcTest extends BitcoindRpcTest {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
client <- clientF
|
client <- clientF
|
||||||
_ <- client.createMultiSig(2,
|
_ <- client.createMultiSig(
|
||||||
Vector(pubKey1, pubKey2),
|
2,
|
||||||
AddressType.Bech32)
|
Vector(pubKey1, pubKey2),
|
||||||
|
AddressType.Bech32
|
||||||
|
)
|
||||||
} yield succeed
|
} yield succeed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,14 +98,20 @@ class RawTransactionRpcTest extends BitcoindRpcTest {
|
|||||||
|
|
||||||
address <- otherClient.getNewAddress
|
address <- otherClient.getNewAddress
|
||||||
|
|
||||||
input0 = TransactionOutPoint(transaction0.txid.flip,
|
input0 = TransactionOutPoint(
|
||||||
UInt32(transaction0.blockindex.get))
|
transaction0.txid.flip,
|
||||||
input1 = TransactionOutPoint(transaction1.txid.flip,
|
UInt32(transaction0.blockindex.get)
|
||||||
UInt32(transaction1.blockindex.get))
|
)
|
||||||
|
input1 = TransactionOutPoint(
|
||||||
|
transaction1.txid.flip,
|
||||||
|
UInt32(transaction1.blockindex.get)
|
||||||
|
)
|
||||||
transaction <- {
|
transaction <- {
|
||||||
val sig: ScriptSignature = ScriptSignature.empty
|
val sig: ScriptSignature = ScriptSignature.empty
|
||||||
val inputs = Vector(TransactionInput(input0, sig, UInt32(1)),
|
val inputs = Vector(
|
||||||
TransactionInput(input1, sig, UInt32(2)))
|
TransactionInput(input0, sig, UInt32(1)),
|
||||||
|
TransactionInput(input1, sig, UInt32(2))
|
||||||
|
)
|
||||||
val outputs = Map(address -> Bitcoins(1))
|
val outputs = Map(address -> Bitcoins(1))
|
||||||
client.createRawTransaction(inputs, outputs)
|
client.createRawTransaction(inputs, outputs)
|
||||||
}
|
}
|
||||||
@ -150,12 +156,16 @@ class RawTransactionRpcTest extends BitcoindRpcTest {
|
|||||||
newAddress <- client.getNewAddress
|
newAddress <- client.getNewAddress
|
||||||
rawCreatedTx <- {
|
rawCreatedTx <- {
|
||||||
val input =
|
val input =
|
||||||
TransactionInput(TransactionOutPoint(txid.flip, UInt32(output.n)),
|
TransactionInput(
|
||||||
EmptyScriptSignature,
|
TransactionOutPoint(txid.flip, UInt32(output.n)),
|
||||||
UInt32.max - UInt32.one)
|
EmptyScriptSignature,
|
||||||
|
UInt32.max - UInt32.one
|
||||||
|
)
|
||||||
client
|
client
|
||||||
.createRawTransaction(Vector(input),
|
.createRawTransaction(
|
||||||
Map(newAddress -> Bitcoins(sendAmt.satoshis)))
|
Vector(input),
|
||||||
|
Map(newAddress -> Bitcoins(sendAmt.satoshis))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
result <- {
|
result <- {
|
||||||
@ -166,7 +176,8 @@ class RawTransactionRpcTest extends BitcoindRpcTest {
|
|||||||
scriptPubKey = ScriptPubKey.fromAsmHex(output.scriptPubKey.hex),
|
scriptPubKey = ScriptPubKey.fromAsmHex(output.scriptPubKey.hex),
|
||||||
redeemScript = None,
|
redeemScript = None,
|
||||||
amount = Some(fundAmt)
|
amount = Some(fundAmt)
|
||||||
))
|
)
|
||||||
|
)
|
||||||
BitcoindRpcTestUtil.signRawTransaction(
|
BitcoindRpcTestUtil.signRawTransaction(
|
||||||
client,
|
client,
|
||||||
rawCreatedTx,
|
rawCreatedTx,
|
||||||
@ -183,7 +194,8 @@ class RawTransactionRpcTest extends BitcoindRpcTest {
|
|||||||
.createRawTransaction(Vector(), Map(address -> Bitcoins(1)))
|
.createRawTransaction(Vector(), Map(address -> Bitcoins(1)))
|
||||||
.flatMap { tx =>
|
.flatMap { tx =>
|
||||||
recoverToSucceededIf[InvalidAddressOrKey](
|
recoverToSucceededIf[InvalidAddressOrKey](
|
||||||
client.abandonTransaction(tx.txId))
|
client.abandonTransaction(tx.txId)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,10 @@ class UTXORpcTest extends BitcoindRpcTest {
|
|||||||
|
|
||||||
val vout1 = unspent(0).vout
|
val vout1 = unspent(0).vout
|
||||||
val vout2 = unspent(1).vout
|
val vout2 = unspent(1).vout
|
||||||
Vector(RpcOpts.LockUnspentOutputParameter(txid1, vout1),
|
Vector(
|
||||||
RpcOpts.LockUnspentOutputParameter(txid2, vout2))
|
RpcOpts.LockUnspentOutputParameter(txid1, vout1),
|
||||||
|
RpcOpts.LockUnspentOutputParameter(txid2, vout2)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
firstSuccess <- client.lockUnspent(unlock = false, param)
|
firstSuccess <- client.lockUnspent(unlock = false, param)
|
||||||
locked <- client.listLockUnspent
|
locked <- client.listLockUnspent
|
||||||
|
@ -52,7 +52,8 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
lazy val walletClientF: Future[BitcoindRpcClient] = clientsF.flatMap { _ =>
|
lazy val walletClientF: Future[BitcoindRpcClient] = clientsF.flatMap { _ =>
|
||||||
val walletClient =
|
val walletClient =
|
||||||
BitcoindRpcClient.withActorSystem(
|
BitcoindRpcClient.withActorSystem(
|
||||||
BitcoindRpcTestUtil.instance(versionOpt = Some(BitcoindVersion.newest)))
|
BitcoindRpcTestUtil.instance(versionOpt = Some(BitcoindVersion.newest))
|
||||||
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
_ <- startClient(walletClient)
|
_ <- startClient(walletClient)
|
||||||
@ -126,10 +127,12 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
for {
|
for {
|
||||||
_ <- {
|
_ <- {
|
||||||
val addrFuts =
|
val addrFuts =
|
||||||
List(client.getNewAddress,
|
List(
|
||||||
client.getNewAddress(AddressType.Bech32),
|
client.getNewAddress,
|
||||||
client.getNewAddress(AddressType.P2SHSegwit),
|
client.getNewAddress(AddressType.Bech32),
|
||||||
client.getNewAddress(AddressType.Legacy))
|
client.getNewAddress(AddressType.P2SHSegwit),
|
||||||
|
client.getNewAddress(AddressType.Legacy)
|
||||||
|
)
|
||||||
Future.sequence(addrFuts)
|
Future.sequence(addrFuts)
|
||||||
}
|
}
|
||||||
} yield succeed
|
} yield succeed
|
||||||
@ -166,8 +169,10 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
val client = nodePair.node1
|
val client = nodePair.node1
|
||||||
for {
|
for {
|
||||||
balance <- client.getUnconfirmedBalance
|
balance <- client.getUnconfirmedBalance
|
||||||
transaction <- BitcoindRpcTestUtil.sendCoinbaseTransaction(client,
|
transaction <- BitcoindRpcTestUtil.sendCoinbaseTransaction(
|
||||||
client)
|
client,
|
||||||
|
client
|
||||||
|
)
|
||||||
newBalance <- client.getUnconfirmedBalance
|
newBalance <- client.getUnconfirmedBalance
|
||||||
} yield {
|
} yield {
|
||||||
assert(balance == Bitcoins(0))
|
assert(balance == Bitcoins(0))
|
||||||
@ -188,7 +193,7 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it should "be able to refill the keypool" ignore { nodePair: FixtureParam =>
|
it should "be able to refill the keypool" ignore { nodePair: FixtureParam =>
|
||||||
//ignore until: https://github.com/bitcoin/bitcoin/issues/29924
|
// ignore until: https://github.com/bitcoin/bitcoin/issues/29924
|
||||||
val client = nodePair.node1
|
val client = nodePair.node1
|
||||||
for {
|
for {
|
||||||
info <- client.getWalletInfo
|
info <- client.getWalletInfo
|
||||||
@ -228,15 +233,18 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
def getChangeAddressAndAmount(
|
def getChangeAddressAndAmount(
|
||||||
client: BitcoindRpcClient,
|
client: BitcoindRpcClient,
|
||||||
address: BitcoinAddress,
|
address: BitcoinAddress,
|
||||||
txid: DoubleSha256DigestBE): Future[(BitcoinAddress, CurrencyUnit)] = {
|
txid: DoubleSha256DigestBE
|
||||||
|
): Future[(BitcoinAddress, CurrencyUnit)] = {
|
||||||
for {
|
for {
|
||||||
rawTx <- client.getRawTransactionRaw(txid)
|
rawTx <- client.getRawTransactionRaw(txid)
|
||||||
} yield {
|
} yield {
|
||||||
val outs = rawTx.outputs.filterNot(_.value == amount)
|
val outs = rawTx.outputs.filterNot(_.value == amount)
|
||||||
val changeAddresses = outs
|
val changeAddresses = outs
|
||||||
.map(out =>
|
.map(out =>
|
||||||
(BitcoinAddress.fromScriptPubKey(out.scriptPubKey, networkParam),
|
(
|
||||||
out.value))
|
BitcoinAddress.fromScriptPubKey(out.scriptPubKey, networkParam),
|
||||||
|
out.value
|
||||||
|
))
|
||||||
assert(changeAddresses.size == 1)
|
assert(changeAddresses.size == 1)
|
||||||
assert(changeAddresses.head._1 != address)
|
assert(changeAddresses.head._1 != address)
|
||||||
(changeAddresses.head._1, changeAddresses.head._2)
|
(changeAddresses.head._1, changeAddresses.head._2)
|
||||||
@ -248,10 +256,12 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
|
|
||||||
address <- client.getNewAddress
|
address <- client.getNewAddress
|
||||||
|
|
||||||
txid <- BitcoindRpcTestUtil.fundBlockChainTransaction(client,
|
txid <- BitcoindRpcTestUtil.fundBlockChainTransaction(
|
||||||
otherClient,
|
client,
|
||||||
address,
|
otherClient,
|
||||||
amount)
|
address,
|
||||||
|
amount
|
||||||
|
)
|
||||||
|
|
||||||
(changeAddress, changeAmount) <-
|
(changeAddress, changeAmount) <-
|
||||||
getChangeAddressAndAmount(client, address, txid)
|
getChangeAddressAndAmount(client, address, txid)
|
||||||
@ -269,7 +279,8 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
|
|
||||||
// the change address should be added to an exiting address grouping
|
// the change address should be added to an exiting address grouping
|
||||||
assert(
|
assert(
|
||||||
!groupingsBefore.exists(vec => vec.exists(_.address == changeAddress)))
|
!groupingsBefore.exists(vec => vec.exists(_.address == changeAddress))
|
||||||
|
)
|
||||||
|
|
||||||
val changeGroupingOpt =
|
val changeGroupingOpt =
|
||||||
groupingsAfter.find(vec => vec.exists(_.address == changeAddress))
|
groupingsAfter.find(vec => vec.exists(_.address == changeAddress))
|
||||||
@ -324,10 +335,12 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
address <- otherClient.getNewAddress
|
address <- otherClient.getNewAddress
|
||||||
txid <-
|
txid <-
|
||||||
BitcoindRpcTestUtil
|
BitcoindRpcTestUtil
|
||||||
.fundBlockChainTransaction(client,
|
.fundBlockChainTransaction(
|
||||||
otherClient,
|
client,
|
||||||
address,
|
otherClient,
|
||||||
Bitcoins(1.5))
|
address,
|
||||||
|
Bitcoins(1.5)
|
||||||
|
)
|
||||||
receivedList <- otherClient.listReceivedByAddress()
|
receivedList <- otherClient.listReceivedByAddress()
|
||||||
} yield {
|
} yield {
|
||||||
val entryList =
|
val entryList =
|
||||||
@ -348,10 +361,12 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
address <- otherClient.getNewAddress
|
address <- otherClient.getNewAddress
|
||||||
txid <-
|
txid <-
|
||||||
BitcoindRpcTestUtil
|
BitcoindRpcTestUtil
|
||||||
.fundBlockChainTransaction(client,
|
.fundBlockChainTransaction(
|
||||||
otherClient,
|
client,
|
||||||
address,
|
otherClient,
|
||||||
Bitcoins(1.5))
|
address,
|
||||||
|
Bitcoins(1.5)
|
||||||
|
)
|
||||||
txs <- otherClient.listTransactions()
|
txs <- otherClient.listTransactions()
|
||||||
} yield {
|
} yield {
|
||||||
assert(txs.nonEmpty)
|
assert(txs.nonEmpty)
|
||||||
@ -419,12 +434,15 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
TransactionInput(
|
TransactionInput(
|
||||||
TransactionOutPoint(output.txid.flip, UInt32(output.vout)),
|
TransactionOutPoint(output.txid.flip, UInt32(output.vout)),
|
||||||
ScriptSignature.empty,
|
ScriptSignature.empty,
|
||||||
UInt32.max - UInt32(2))
|
UInt32.max - UInt32(2)
|
||||||
|
)
|
||||||
val inputs = Vector(input)
|
val inputs = Vector(input)
|
||||||
|
|
||||||
val outputs =
|
val outputs =
|
||||||
Map(address -> Bitcoins(0.5),
|
Map(
|
||||||
changeAddress -> Bitcoins(output.amount.toBigDecimal - 0.55))
|
address -> Bitcoins(0.5),
|
||||||
|
changeAddress -> Bitcoins(output.amount.toBigDecimal - 0.55)
|
||||||
|
)
|
||||||
|
|
||||||
client.createRawTransaction(inputs, outputs)
|
client.createRawTransaction(inputs, outputs)
|
||||||
}
|
}
|
||||||
@ -453,7 +471,9 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
} yield {
|
} yield {
|
||||||
assert(
|
assert(
|
||||||
transaction.outputs.contains(
|
transaction.outputs.contains(
|
||||||
TransactionOutput(Bitcoins(1), address.scriptPubKey)))
|
TransactionOutput(Bitcoins(1), address.scriptPubKey)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,23 +487,31 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
val spk = P2WPKHWitnessSPKV0(privKey.publicKey)
|
val spk = P2WPKHWitnessSPKV0(privKey.publicKey)
|
||||||
val importedAddress = Bech32Address.fromScriptPubKey(spk, np)
|
val importedAddress = Bech32Address.fromScriptPubKey(spk, np)
|
||||||
for {
|
for {
|
||||||
fundingTxId <- otherClient.sendToAddress(importedAddress,
|
fundingTxId <- otherClient.sendToAddress(
|
||||||
Bitcoins(1.01))
|
importedAddress,
|
||||||
|
Bitcoins(1.01)
|
||||||
|
)
|
||||||
_ <- otherClient.generate(1)
|
_ <- otherClient.generate(1)
|
||||||
vout <- otherClient
|
vout <- otherClient
|
||||||
.getRawTransactionRaw(fundingTxId)
|
.getRawTransactionRaw(fundingTxId)
|
||||||
.map(_.outputs.zipWithIndex.find(
|
.map(
|
||||||
_._1.scriptPubKey == descriptor.scriptPubKey))
|
_.outputs.zipWithIndex
|
||||||
|
.find(_._1.scriptPubKey == descriptor.scriptPubKey)
|
||||||
|
)
|
||||||
.map(_.get._2)
|
.map(_.get._2)
|
||||||
fundingPrevOut = TransactionOutPoint(fundingTxId, vout)
|
fundingPrevOut = TransactionOutPoint(fundingTxId, vout)
|
||||||
fundingInput = TransactionInput(fundingPrevOut,
|
fundingInput = TransactionInput(
|
||||||
ScriptSignature.empty,
|
fundingPrevOut,
|
||||||
TransactionConstants.sequence)
|
ScriptSignature.empty,
|
||||||
|
TransactionConstants.sequence
|
||||||
|
)
|
||||||
address <- otherClient.getNewAddress
|
address <- otherClient.getNewAddress
|
||||||
transaction <-
|
transaction <-
|
||||||
client
|
client
|
||||||
.createRawTransaction(inputs = Vector(fundingInput),
|
.createRawTransaction(
|
||||||
outputs = Map(address -> Bitcoins.one))
|
inputs = Vector(fundingInput),
|
||||||
|
outputs = Map(address -> Bitcoins.one)
|
||||||
|
)
|
||||||
signedTx <- client
|
signedTx <- client
|
||||||
.signRawTransactionWithKey(transaction, Vector(privKey))
|
.signRawTransactionWithKey(transaction, Vector(privKey))
|
||||||
.map(_.hex)
|
.map(_.hex)
|
||||||
@ -499,7 +527,8 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
P2WPKHV0InputInfo(outPoint, output.value, privKey.publicKey),
|
P2WPKHV0InputInfo(outPoint, output.value, privKey.publicKey),
|
||||||
prevTx,
|
prevTx,
|
||||||
privKey,
|
privKey,
|
||||||
HashType.sigHashAll),
|
HashType.sigHashAll
|
||||||
|
),
|
||||||
transaction,
|
transaction,
|
||||||
isDummySignature = false
|
isDummySignature = false
|
||||||
)
|
)
|
||||||
@ -507,7 +536,8 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
signedTx match {
|
signedTx match {
|
||||||
case btx: NonWitnessTransaction =>
|
case btx: NonWitnessTransaction =>
|
||||||
assert(
|
assert(
|
||||||
btx.inputs.head.scriptSignature.signatures.head == partialSig.signature)
|
btx.inputs.head.scriptSignature.signatures.head == partialSig.signature
|
||||||
|
)
|
||||||
case wtx: WitnessTransaction =>
|
case wtx: WitnessTransaction =>
|
||||||
wtx.witness.head match {
|
wtx.witness.head match {
|
||||||
case p2wpkh: P2WPKHWitnessV0 =>
|
case p2wpkh: P2WPKHWitnessV0 =>
|
||||||
@ -552,7 +582,8 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
|
|
||||||
val psbt =
|
val psbt =
|
||||||
PSBT.fromBase64(
|
PSBT.fromBase64(
|
||||||
"cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA==")
|
"cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA=="
|
||||||
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
result <- client.utxoUpdatePsbt(psbt, Seq(descriptor))
|
result <- client.utxoUpdatePsbt(psbt, Seq(descriptor))
|
||||||
@ -578,15 +609,19 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest {
|
|||||||
val pubKey2 = ECPublicKey.freshPublicKey
|
val pubKey2 = ECPublicKey.freshPublicKey
|
||||||
|
|
||||||
for {
|
for {
|
||||||
multiSigResult <- client.createMultiSig(2,
|
multiSigResult <- client.createMultiSig(
|
||||||
Vector(pubKey1, pubKey2),
|
2,
|
||||||
AddressType.Bech32)
|
Vector(pubKey1, pubKey2),
|
||||||
|
AddressType.Bech32
|
||||||
|
)
|
||||||
} yield {
|
} yield {
|
||||||
// just validate we are able to receive a sane descriptor
|
// just validate we are able to receive a sane descriptor
|
||||||
// no need to check checksum
|
// no need to check checksum
|
||||||
assert(
|
assert(
|
||||||
multiSigResult.descriptor.startsWith(
|
multiSigResult.descriptor.startsWith(
|
||||||
s"wsh(multi(2,${pubKey1.hex},${pubKey2.hex}))#"))
|
s"wsh(multi(2,${pubKey1.hex},${pubKey2.hex}))#"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,10 +17,12 @@ class BitcoindConfigTest extends BitcoinSUnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it must "parse networks" in {
|
it must "parse networks" in {
|
||||||
val conf = BitcoindConfig("""
|
val conf = BitcoindConfig(
|
||||||
|
"""
|
||||||
|regtest=1
|
|regtest=1
|
||||||
""".stripMargin,
|
""".stripMargin,
|
||||||
tmpDir)
|
tmpDir
|
||||||
|
)
|
||||||
assert(conf.network == RegTest)
|
assert(conf.network == RegTest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,8 @@ import org.bitcoins.rpc.client.common.BitcoindRpcClient
|
|||||||
import org.bitcoins.testkit.rpc.BitcoindFixturesFundedCachedNewest
|
import org.bitcoins.testkit.rpc.BitcoindFixturesFundedCachedNewest
|
||||||
|
|
||||||
/** Tests for PSBT for RPC calls specific to V18 new PSBT calls
|
/** Tests for PSBT for RPC calls specific to V18 new PSBT calls
|
||||||
* @see https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#test-vectors
|
* @see
|
||||||
|
* https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#test-vectors
|
||||||
*/
|
*/
|
||||||
class PsbtRpcTest extends BitcoindFixturesFundedCachedNewest {
|
class PsbtRpcTest extends BitcoindFixturesFundedCachedNewest {
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ class PsbtRpcTest extends BitcoindFixturesFundedCachedNewest {
|
|||||||
|
|
||||||
it should "return something when analyzePsbt is called" in {
|
it should "return something when analyzePsbt is called" in {
|
||||||
client: BitcoindRpcClient =>
|
client: BitcoindRpcClient =>
|
||||||
//PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled.
|
// PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled.
|
||||||
val psbt =
|
val psbt =
|
||||||
"cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="
|
"cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ class PsbtRpcTest extends BitcoindFixturesFundedCachedNewest {
|
|||||||
}
|
}
|
||||||
it should "analyze a PSBT and return a non-empty result" in {
|
it should "analyze a PSBT and return a non-empty result" in {
|
||||||
client: BitcoindRpcClient =>
|
client: BitcoindRpcClient =>
|
||||||
//PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled.
|
// PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled.
|
||||||
|
|
||||||
val psbt =
|
val psbt =
|
||||||
"cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="
|
"cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="
|
||||||
@ -47,7 +48,7 @@ class PsbtRpcTest extends BitcoindFixturesFundedCachedNewest {
|
|||||||
}
|
}
|
||||||
it should "correctly analyze a psbt " in { client: BitcoindRpcClient =>
|
it should "correctly analyze a psbt " in { client: BitcoindRpcClient =>
|
||||||
val psbt =
|
val psbt =
|
||||||
//PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled.
|
// PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled.
|
||||||
"cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="
|
"cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="
|
||||||
val analyzedF = client.analyzePsbt(PSBT.fromBase64(psbt))
|
val analyzedF = client.analyzePsbt(PSBT.fromBase64(psbt))
|
||||||
val expectedfee = Bitcoins(0.00090341)
|
val expectedfee = Bitcoins(0.00090341)
|
||||||
@ -70,12 +71,13 @@ class PsbtRpcTest extends BitcoindFixturesFundedCachedNewest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Todo: figure out how to implement a test here
|
// Todo: figure out how to implement a test here
|
||||||
it should "check to see if the utxoUpdate input has been updated" in {
|
it should "check to see if the utxoUpdate input has been updated" in {
|
||||||
client: BitcoindRpcClient =>
|
client: BitcoindRpcClient =>
|
||||||
val psbt =
|
val psbt =
|
||||||
PSBT.fromBase64(
|
PSBT.fromBase64(
|
||||||
"cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA==")
|
"cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA=="
|
||||||
|
)
|
||||||
val updatedF = client.utxoUpdatePsbt(psbt)
|
val updatedF = client.utxoUpdatePsbt(psbt)
|
||||||
|
|
||||||
updatedF.map { result =>
|
updatedF.map { result =>
|
||||||
@ -83,16 +85,18 @@ class PsbtRpcTest extends BitcoindFixturesFundedCachedNewest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Join psbt looks at the characteristics of a vector of PSBTs and converts them into a singular PSBT.
|
/** Join psbt looks at the characteristics of a vector of PSBTs and converts
|
||||||
* This test takes test vectors from BIP 157 each missing some characteristic covered by the other. When joined
|
* them into a singular PSBT. This test takes test vectors from BIP 157 each
|
||||||
* together the resulting PSBT represented as a string is very different so we can't just search for parts of either
|
* missing some characteristic covered by the other. When joined together the
|
||||||
* PSBT.
|
* resulting PSBT represented as a string is very different so we can't just
|
||||||
|
* search for parts of either PSBT.
|
||||||
*/
|
*/
|
||||||
it should "joinpsbts" in { client: BitcoindRpcClient =>
|
it should "joinpsbts" in { client: BitcoindRpcClient =>
|
||||||
val seqofpsbts = Vector(
|
val seqofpsbts = Vector(
|
||||||
PSBT.fromBase64(
|
PSBT.fromBase64(
|
||||||
"cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA"),
|
"cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA"
|
||||||
//PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled.
|
),
|
||||||
|
// PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled.
|
||||||
PSBT.fromBase64(
|
PSBT.fromBase64(
|
||||||
"cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="
|
"cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="
|
||||||
)
|
)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user