mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-19 05:43:51 +01:00
Move RPC server logic into separate project (#2440)
This commit is contained in:
parent
b44aedacca
commit
214dba8a8f
@ -8,7 +8,7 @@ import org.bitcoins.core.protocol.tlv._
|
||||
import org.bitcoins.dlc.oracle._
|
||||
import org.bitcoins.dlc.oracle.config.DLCOracleAppConfig
|
||||
import org.bitcoins.keymanager.WalletStorage
|
||||
import org.bitcoins.server._
|
||||
import org.bitcoins.server.routes.{Server, ServerCommand, ServerRoute}
|
||||
import ujson._
|
||||
|
||||
import scala.util.{Failure, Success}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package org.bitcoins.oracle.server
|
||||
|
||||
import org.bitcoins.dlc.oracle.config.DLCOracleAppConfig
|
||||
import org.bitcoins.server.{BitcoinSRunner, Server}
|
||||
import org.bitcoins.server.routes.{BitcoinSRunner, Server}
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
|
@ -0,0 +1,329 @@
|
||||
package org.bitcoins.oracle.server
|
||||
|
||||
import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.LockUnspentOutputParameter
|
||||
import org.bitcoins.core.api.wallet.CoinSelectionAlgo
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.tlv._
|
||||
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionOutPoint}
|
||||
import org.bitcoins.core.psbt.PSBT
|
||||
import org.bitcoins.crypto.AesPassword
|
||||
import ujson._
|
||||
|
||||
import java.time.Instant
|
||||
import scala.util.{Failure, Try}
|
||||
|
||||
case class CreateEvent(
|
||||
label: String,
|
||||
maturationTime: Instant,
|
||||
outcomes: Vector[String])
|
||||
|
||||
object CreateEvent extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[CreateEvent] = {
|
||||
jsArr.arr.toList match {
|
||||
case labelJs :: maturationTimeJs :: outcomesJs :: Nil =>
|
||||
Try {
|
||||
val label = labelJs.str
|
||||
val maturationTime: Instant =
|
||||
Instant.ofEpochSecond(maturationTimeJs.num.toLong)
|
||||
val outcomes = outcomesJs.arr.map(_.str).toVector
|
||||
|
||||
CreateEvent(label, maturationTime, outcomes)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(
|
||||
new IllegalArgumentException("Missing label and outcome arguments"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class CreateRangedEvent(
|
||||
eventName: String,
|
||||
maturationTime: Instant,
|
||||
start: Int,
|
||||
stop: Int,
|
||||
step: Int,
|
||||
unit: String,
|
||||
precision: Int)
|
||||
|
||||
object CreateRangedEvent extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[CreateRangedEvent] = {
|
||||
jsArr.arr.toList match {
|
||||
case labelJs :: maturationTimeJs :: startJs :: stopJs :: stepJs :: unitJs :: precisionJs :: Nil =>
|
||||
Try {
|
||||
val label = labelJs.str
|
||||
val maturationTime: Instant =
|
||||
Instant.ofEpochSecond(maturationTimeJs.num.toLong)
|
||||
val start = startJs.num.toInt
|
||||
val stop = stopJs.num.toInt
|
||||
val step = stepJs.num.toInt
|
||||
val unit = unitJs.str
|
||||
val precision = precisionJs.num.toInt
|
||||
|
||||
CreateRangedEvent(label,
|
||||
maturationTime,
|
||||
start,
|
||||
stop,
|
||||
step,
|
||||
unit,
|
||||
precision)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Missing label, maturationTime, start, stop, and step arguments"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 5"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class CreateDigitDecompEvent(
|
||||
eventName: String,
|
||||
maturationTime: Instant,
|
||||
base: Int,
|
||||
isSigned: Boolean,
|
||||
numDigits: Int,
|
||||
unit: String,
|
||||
precision: Int)
|
||||
|
||||
object CreateDigitDecompEvent extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[CreateDigitDecompEvent] = {
|
||||
jsArr.arr.toList match {
|
||||
case labelJs :: maturationTimeJs :: baseJs :: isSignedJs :: numDigitsJs :: unitJs :: precisionJs :: Nil =>
|
||||
Try {
|
||||
val label = labelJs.str
|
||||
val maturationTime: Instant =
|
||||
Instant.ofEpochSecond(maturationTimeJs.num.toLong)
|
||||
val base = baseJs.num.toInt
|
||||
val isSigned = isSignedJs.bool
|
||||
val numDigits = numDigitsJs.num.toInt
|
||||
val unit = unitJs.str
|
||||
val precision = precisionJs.num.toInt
|
||||
|
||||
CreateDigitDecompEvent(label,
|
||||
maturationTime,
|
||||
base,
|
||||
isSigned,
|
||||
numDigits,
|
||||
unit,
|
||||
precision)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(new IllegalArgumentException(
|
||||
"Missing label, maturationTime, base, isSigned, and numDigits arguments"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 5"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class SignEvent(oracleEventTLV: OracleEventV0TLV, outcome: String)
|
||||
|
||||
object SignEvent extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[SignEvent] = {
|
||||
jsArr.arr.toList match {
|
||||
case tlvJs :: outcomeJs :: Nil =>
|
||||
Try {
|
||||
val oracleEventTLV = OracleEventV0TLV(tlvJs.str)
|
||||
val outcome = outcomeJs.str
|
||||
|
||||
SignEvent(oracleEventTLV, outcome)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Missing oracle event tlv and outcome arguments"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class SignForRange(oracleEventTLV: OracleEventV0TLV, num: Long)
|
||||
|
||||
object SignForRange extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[SignForRange] = {
|
||||
jsArr.arr.toList match {
|
||||
case tlvJs :: numJs :: Nil =>
|
||||
Try {
|
||||
val oracleEventTLV = OracleEventV0TLV(tlvJs.str)
|
||||
val num = numJs match {
|
||||
case num: Num => num.value
|
||||
case str: Str => str.value.toDouble
|
||||
case _: Value =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Unable to parse $numJs as a number")
|
||||
}
|
||||
|
||||
SignForRange(oracleEventTLV, num.toLong)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Missing oracle event tlv and num arguments"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class SignDigits(oracleEventTLV: OracleEventV0TLV, num: Long)
|
||||
|
||||
object SignDigits extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[SignDigits] = {
|
||||
jsArr.arr.toList match {
|
||||
case tlvJs :: numJs :: Nil =>
|
||||
Try {
|
||||
val oracleEventTLV = OracleEventV0TLV(tlvJs.str)
|
||||
val num = numJs match {
|
||||
case num: Num => num.value
|
||||
case str: Str => str.value.toDouble
|
||||
case _: Value =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Unable to parse $numJs as a number")
|
||||
}
|
||||
|
||||
SignDigits(oracleEventTLV, num.toLong)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Missing oracle event tlv and num arguments"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class GetEvent(oracleEventTLV: OracleEventV0TLV)
|
||||
|
||||
object GetEvent extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[GetEvent] = {
|
||||
require(jsArr.arr.size == 1,
|
||||
s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1")
|
||||
Try {
|
||||
val oracleEventTLV = OracleEventV0TLV(jsArr.arr.head.str)
|
||||
|
||||
GetEvent(oracleEventTLV)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class KeyManagerPassphraseChange(
|
||||
oldPassword: AesPassword,
|
||||
newPassword: AesPassword)
|
||||
|
||||
object KeyManagerPassphraseChange extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[KeyManagerPassphraseChange] = {
|
||||
jsArr.arr.toList match {
|
||||
case oldPassJs :: newPassJs :: Nil =>
|
||||
Try {
|
||||
val oldPass = AesPassword.fromString(oldPassJs.str)
|
||||
val newPass = AesPassword.fromString(newPassJs.str)
|
||||
|
||||
KeyManagerPassphraseChange(oldPass, newPass)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Missing old password and new password arguments"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class KeyManagerPassphraseSet(password: AesPassword)
|
||||
|
||||
object KeyManagerPassphraseSet extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[KeyManagerPassphraseSet] = {
|
||||
jsArr.arr.toList match {
|
||||
case passJs :: Nil =>
|
||||
Try {
|
||||
val pass = AesPassword.fromString(passJs.str)
|
||||
|
||||
KeyManagerPassphraseSet(pass)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(new IllegalArgumentException("Missing password argument"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 1"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait ServerJsonModels {
|
||||
|
||||
def jsToBitcoinAddress(js: Value): BitcoinAddress = {
|
||||
try {
|
||||
BitcoinAddress.fromString(js.str)
|
||||
} catch {
|
||||
case _: IllegalArgumentException =>
|
||||
throw Value.InvalidData(js, "Expected a valid address")
|
||||
}
|
||||
}
|
||||
|
||||
def jsToPSBTSeq(js: Value): Seq[PSBT] = {
|
||||
js.arr.foldLeft(Seq.empty[PSBT])((seq, psbt) => seq :+ jsToPSBT(psbt))
|
||||
}
|
||||
|
||||
def jsToPSBT(js: Value): PSBT = PSBT.fromString(js.str)
|
||||
|
||||
def jsToTransactionOutPointSeq(js: Value): Seq[TransactionOutPoint] = {
|
||||
js.arr.foldLeft(Seq.empty[TransactionOutPoint])((seq, outPoint) =>
|
||||
seq :+ jsToTransactionOutPoint(outPoint))
|
||||
}
|
||||
|
||||
def jsToTransactionOutPoint(js: Value): TransactionOutPoint =
|
||||
TransactionOutPoint(js.str)
|
||||
|
||||
def jsToLockUnspentOutputParameter(js: Value): LockUnspentOutputParameter =
|
||||
LockUnspentOutputParameter.fromJson(js)
|
||||
|
||||
def jsToLockUnspentOutputParameters(
|
||||
js: Value): Seq[LockUnspentOutputParameter] = {
|
||||
js.arr.foldLeft(Seq.empty[LockUnspentOutputParameter])((seq, outPoint) =>
|
||||
seq :+ jsToLockUnspentOutputParameter(outPoint))
|
||||
}
|
||||
|
||||
def jsToCoinSelectionAlgo(js: Value): CoinSelectionAlgo =
|
||||
CoinSelectionAlgo
|
||||
.fromString(js.str)
|
||||
|
||||
def jsToTx(js: Value): Transaction = Transaction.fromHex(js.str)
|
||||
|
||||
def nullToOpt(value: Value): Option[Value] =
|
||||
value match {
|
||||
case Null => None
|
||||
case Arr(arr) if arr.isEmpty => None
|
||||
case Arr(arr) if arr.size == 1 => Some(arr.head)
|
||||
case _: Value => Some(value)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.bitcoins.server
|
||||
package org.bitcoins.server.routes
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import com.typesafe.config.{Config, ConfigFactory}
|
@ -1,4 +1,4 @@
|
||||
package org.bitcoins.server
|
||||
package org.bitcoins.server.routes
|
||||
|
||||
/** HTTP errors our server knows how to handle.
|
||||
* These gets picked up by the exceptions handler
|
@ -1,4 +1,4 @@
|
||||
package org.bitcoins.server
|
||||
package org.bitcoins.server.routes
|
||||
|
||||
import grizzled.slf4j.Logging
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.bitcoins.server
|
||||
package org.bitcoins.server.routes
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.event.Logging
|
||||
@ -59,7 +59,7 @@ case class Server(
|
||||
}
|
||||
}
|
||||
|
||||
val route =
|
||||
val route: Route =
|
||||
// TODO implement better logging
|
||||
DebuggingDirectives.logRequestResult("http-rpc-server", Logging.InfoLevel) {
|
||||
withErrorHandling {
|
@ -0,0 +1,26 @@
|
||||
package org.bitcoins.server.routes
|
||||
|
||||
import ujson._
|
||||
import upickle.default._
|
||||
|
||||
// TODO ID?
|
||||
case class ServerCommand(method: String, params: ujson.Arr)
|
||||
|
||||
object ServerCommand {
|
||||
|
||||
implicit val rw: ReadWriter[ServerCommand] =
|
||||
readwriter[ujson.Value].bimap[ServerCommand](
|
||||
cmd => {
|
||||
if (cmd.params.arr.isEmpty)
|
||||
Obj("method" -> Str(cmd.method))
|
||||
else Obj("method" -> Str(cmd.method), "params" -> cmd.params)
|
||||
},
|
||||
json => {
|
||||
val obj = json.obj
|
||||
val method = obj("method").str
|
||||
if (obj.contains("params"))
|
||||
ServerCommand(method, obj("params").arr)
|
||||
else ServerCommand(method, Arr())
|
||||
}
|
||||
)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.bitcoins.server
|
||||
package org.bitcoins.server.routes
|
||||
|
||||
import akka.http.scaladsl.server.StandardRoute
|
||||
|
@ -35,6 +35,7 @@ import org.bitcoins.crypto.{
|
||||
}
|
||||
import org.bitcoins.node.Node
|
||||
import org.bitcoins.server.BitcoinSAppConfig.implicitToWalletConf
|
||||
import org.bitcoins.server.routes.ServerCommand
|
||||
import org.bitcoins.testkit.BitcoinSTestAppConfig
|
||||
import org.bitcoins.wallet.MockWalletApi
|
||||
import org.scalamock.scalatest.MockFactory
|
||||
|
@ -3,6 +3,7 @@ package org.bitcoins.server
|
||||
import akka.actor.ActorSystem
|
||||
import akka.dispatch.Dispatchers
|
||||
import akka.http.scaladsl.Http
|
||||
import grizzled.slf4j.Logging
|
||||
import org.bitcoins.chain.blockchain.ChainHandler
|
||||
import org.bitcoins.chain.config.ChainAppConfig
|
||||
import org.bitcoins.chain.models._
|
||||
@ -18,13 +19,15 @@ import org.bitcoins.feeprovider._
|
||||
import org.bitcoins.node._
|
||||
import org.bitcoins.node.config.NodeAppConfig
|
||||
import org.bitcoins.node.models.Peer
|
||||
import org.bitcoins.server.routes.{BitcoinSRunner, Server}
|
||||
import org.bitcoins.wallet.Wallet
|
||||
import org.bitcoins.wallet.config.WalletAppConfig
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future, Promise}
|
||||
|
||||
class BitcoinSServerMain(override val args: Array[String])
|
||||
extends BitcoinSRunner {
|
||||
extends BitcoinSRunner
|
||||
with Logging {
|
||||
|
||||
override val actorSystemName = "bitcoin-s-server"
|
||||
|
||||
@ -288,26 +291,24 @@ class BitcoinSServerMain(override val args: Array[String])
|
||||
val server = {
|
||||
rpcPortOpt match {
|
||||
case Some(rpcport) =>
|
||||
Server.apply(conf = nodeConf,
|
||||
handlers =
|
||||
Seq(walletRoutes, nodeRoutes, chainRoutes, coreRoutes),
|
||||
rpcbindOpt = rpcbindOpt,
|
||||
rpcport = rpcport)
|
||||
Server(conf = nodeConf,
|
||||
handlers =
|
||||
Seq(walletRoutes, nodeRoutes, chainRoutes, coreRoutes),
|
||||
rpcbindOpt = rpcbindOpt,
|
||||
rpcport = rpcport)
|
||||
case None =>
|
||||
conf.rpcPortOpt match {
|
||||
case Some(rpcport) =>
|
||||
Server.apply(
|
||||
conf = nodeConf,
|
||||
handlers =
|
||||
Seq(walletRoutes, nodeRoutes, chainRoutes, coreRoutes),
|
||||
rpcbindOpt = rpcbindOpt,
|
||||
rpcport = rpcport)
|
||||
Server(conf = nodeConf,
|
||||
handlers =
|
||||
Seq(walletRoutes, nodeRoutes, chainRoutes, coreRoutes),
|
||||
rpcbindOpt = rpcbindOpt,
|
||||
rpcport = rpcport)
|
||||
case None =>
|
||||
Server.apply(
|
||||
conf = nodeConf,
|
||||
handlers =
|
||||
Seq(walletRoutes, nodeRoutes, chainRoutes, coreRoutes),
|
||||
rpcbindOpt = rpcbindOpt)
|
||||
Server(conf = nodeConf,
|
||||
handlers =
|
||||
Seq(walletRoutes, nodeRoutes, chainRoutes, coreRoutes),
|
||||
rpcbindOpt = rpcbindOpt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import org.bitcoins.commons.jsonmodels.BitcoinSServerInfo
|
||||
import org.bitcoins.commons.serializers.Picklers._
|
||||
import org.bitcoins.core.api.chain.ChainApi
|
||||
import org.bitcoins.core.config.BitcoinNetwork
|
||||
import org.bitcoins.server.routes.{Server, ServerCommand, ServerRoute}
|
||||
import scodec.bits.ByteVector
|
||||
import ujson._
|
||||
|
||||
|
@ -5,6 +5,7 @@ import akka.http.scaladsl.server.Directives._
|
||||
import akka.http.scaladsl.server._
|
||||
import org.bitcoins.commons.jsonmodels.{SerializedPSBT, SerializedTransaction}
|
||||
import org.bitcoins.core.api.core.CoreApi
|
||||
import org.bitcoins.server.routes.{Server, ServerCommand, ServerRoute}
|
||||
import ujson._
|
||||
|
||||
import scala.collection.mutable
|
||||
|
@ -7,6 +7,7 @@ import org.bitcoins.commons.serializers.Picklers._
|
||||
import org.bitcoins.core.api.node.NodeApi
|
||||
import org.bitcoins.node.Node
|
||||
import org.bitcoins.rpc.client.common.BitcoindRpcClient
|
||||
import org.bitcoins.server.routes.{Server, ServerCommand, ServerRoute}
|
||||
|
||||
import scala.concurrent.duration.DurationInt
|
||||
import scala.util.{Failure, Success}
|
||||
|
@ -1,12 +1,10 @@
|
||||
package org.bitcoins.server
|
||||
|
||||
import java.time.Instant
|
||||
import org.bitcoins.commons.jsonmodels.bitcoind.RpcOpts.LockUnspentOutputParameter
|
||||
import org.bitcoins.core.api.wallet.CoinSelectionAlgo
|
||||
import org.bitcoins.core.crypto._
|
||||
import org.bitcoins.core.currency.{Bitcoins, Satoshis}
|
||||
import org.bitcoins.core.protocol.BlockStamp.BlockHeight
|
||||
import org.bitcoins.core.protocol.tlv._
|
||||
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionOutPoint}
|
||||
import org.bitcoins.core.protocol.{BitcoinAddress, BlockStamp}
|
||||
import org.bitcoins.core.psbt.PSBT
|
||||
@ -14,32 +12,9 @@ import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
import org.bitcoins.core.wallet.utxo.AddressLabelTag
|
||||
import org.bitcoins.crypto.{AesPassword, DoubleSha256DigestBE}
|
||||
import ujson._
|
||||
import upickle.default._
|
||||
|
||||
import scala.util.{Failure, Try}
|
||||
|
||||
// TODO ID?
|
||||
case class ServerCommand(method: String, params: ujson.Arr)
|
||||
|
||||
object ServerCommand {
|
||||
|
||||
implicit val rw: ReadWriter[ServerCommand] =
|
||||
readwriter[ujson.Value].bimap[ServerCommand](
|
||||
cmd => {
|
||||
if (cmd.params.arr.isEmpty)
|
||||
Obj("method" -> Str(cmd.method))
|
||||
else Obj("method" -> Str(cmd.method), "params" -> cmd.params)
|
||||
},
|
||||
json => {
|
||||
val obj = json.obj
|
||||
val method = obj("method").str
|
||||
if (obj.contains("params"))
|
||||
ServerCommand(method, obj("params").arr)
|
||||
else ServerCommand(method, Arr())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
case class GetNewAddress(labelOpt: Option[AddressLabelTag])
|
||||
|
||||
object GetNewAddress extends ServerJsonModels {
|
||||
@ -741,226 +716,6 @@ object BumpFee extends ServerJsonModels {
|
||||
}
|
||||
}
|
||||
|
||||
// Oracle Models
|
||||
|
||||
case class CreateEvent(
|
||||
label: String,
|
||||
maturationTime: Instant,
|
||||
outcomes: Vector[String])
|
||||
|
||||
object CreateEvent extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[CreateEvent] = {
|
||||
jsArr.arr.toList match {
|
||||
case labelJs :: maturationTimeJs :: outcomesJs :: Nil =>
|
||||
Try {
|
||||
val label = labelJs.str
|
||||
val maturationTime: Instant =
|
||||
Instant.ofEpochSecond(maturationTimeJs.num.toLong)
|
||||
val outcomes = outcomesJs.arr.map(_.str).toVector
|
||||
|
||||
CreateEvent(label, maturationTime, outcomes)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(
|
||||
new IllegalArgumentException("Missing label and outcome arguments"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class CreateRangedEvent(
|
||||
eventName: String,
|
||||
maturationTime: Instant,
|
||||
start: Int,
|
||||
stop: Int,
|
||||
step: Int,
|
||||
unit: String,
|
||||
precision: Int)
|
||||
|
||||
object CreateRangedEvent extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[CreateRangedEvent] = {
|
||||
jsArr.arr.toList match {
|
||||
case labelJs :: maturationTimeJs :: startJs :: stopJs :: stepJs :: unitJs :: precisionJs :: Nil =>
|
||||
Try {
|
||||
val label = labelJs.str
|
||||
val maturationTime: Instant =
|
||||
Instant.ofEpochSecond(maturationTimeJs.num.toLong)
|
||||
val start = startJs.num.toInt
|
||||
val stop = stopJs.num.toInt
|
||||
val step = stepJs.num.toInt
|
||||
val unit = unitJs.str
|
||||
val precision = precisionJs.num.toInt
|
||||
|
||||
CreateRangedEvent(label,
|
||||
maturationTime,
|
||||
start,
|
||||
stop,
|
||||
step,
|
||||
unit,
|
||||
precision)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Missing label, maturationTime, start, stop, and step arguments"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 5"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class CreateDigitDecompEvent(
|
||||
eventName: String,
|
||||
maturationTime: Instant,
|
||||
base: Int,
|
||||
isSigned: Boolean,
|
||||
numDigits: Int,
|
||||
unit: String,
|
||||
precision: Int)
|
||||
|
||||
object CreateDigitDecompEvent extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[CreateDigitDecompEvent] = {
|
||||
jsArr.arr.toList match {
|
||||
case labelJs :: maturationTimeJs :: baseJs :: isSignedJs :: numDigitsJs :: unitJs :: precisionJs :: Nil =>
|
||||
Try {
|
||||
val label = labelJs.str
|
||||
val maturationTime: Instant =
|
||||
Instant.ofEpochSecond(maturationTimeJs.num.toLong)
|
||||
val base = baseJs.num.toInt
|
||||
val isSigned = isSignedJs.bool
|
||||
val numDigits = numDigitsJs.num.toInt
|
||||
val unit = unitJs.str
|
||||
val precision = precisionJs.num.toInt
|
||||
|
||||
CreateDigitDecompEvent(label,
|
||||
maturationTime,
|
||||
base,
|
||||
isSigned,
|
||||
numDigits,
|
||||
unit,
|
||||
precision)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(new IllegalArgumentException(
|
||||
"Missing label, maturationTime, base, isSigned, and numDigits arguments"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 5"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class SignEvent(oracleEventTLV: OracleEventV0TLV, outcome: String)
|
||||
|
||||
object SignEvent extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[SignEvent] = {
|
||||
jsArr.arr.toList match {
|
||||
case tlvJs :: outcomeJs :: Nil =>
|
||||
Try {
|
||||
val oracleEventTLV = OracleEventV0TLV(tlvJs.str)
|
||||
val outcome = outcomeJs.str
|
||||
|
||||
SignEvent(oracleEventTLV, outcome)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Missing oracle event tlv and outcome arguments"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class SignForRange(oracleEventTLV: OracleEventV0TLV, num: Long)
|
||||
|
||||
object SignForRange extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[SignForRange] = {
|
||||
jsArr.arr.toList match {
|
||||
case tlvJs :: numJs :: Nil =>
|
||||
Try {
|
||||
val oracleEventTLV = OracleEventV0TLV(tlvJs.str)
|
||||
val num = numJs match {
|
||||
case num: Num => num.value
|
||||
case str: Str => str.value.toDouble
|
||||
case _: Value =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Unable to parse $numJs as a number")
|
||||
}
|
||||
|
||||
SignForRange(oracleEventTLV, num.toLong)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Missing oracle event tlv and num arguments"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class SignDigits(oracleEventTLV: OracleEventV0TLV, num: Long)
|
||||
|
||||
object SignDigits extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[SignDigits] = {
|
||||
jsArr.arr.toList match {
|
||||
case tlvJs :: numJs :: Nil =>
|
||||
Try {
|
||||
val oracleEventTLV = OracleEventV0TLV(tlvJs.str)
|
||||
val num = numJs match {
|
||||
case num: Num => num.value
|
||||
case str: Str => str.value.toDouble
|
||||
case _: Value =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Unable to parse $numJs as a number")
|
||||
}
|
||||
|
||||
SignDigits(oracleEventTLV, num.toLong)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
"Missing oracle event tlv and num arguments"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class GetEvent(oracleEventTLV: OracleEventV0TLV)
|
||||
|
||||
object GetEvent extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[GetEvent] = {
|
||||
require(jsArr.arr.size == 1,
|
||||
s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1")
|
||||
Try {
|
||||
val oracleEventTLV = OracleEventV0TLV(jsArr.arr.head.str)
|
||||
|
||||
GetEvent(oracleEventTLV)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait ServerJsonModels {
|
||||
|
||||
def jsToBitcoinAddress(js: Value): BitcoinAddress = {
|
||||
|
@ -12,6 +12,7 @@ import org.bitcoins.core.wallet.utxo.{AddressLabelTagType, TxoState}
|
||||
import org.bitcoins.crypto.NetworkElement
|
||||
import org.bitcoins.keymanager._
|
||||
import org.bitcoins.keymanager.config.KeyManagerAppConfig
|
||||
import org.bitcoins.server.routes.{Server, ServerCommand, ServerRoute}
|
||||
import org.bitcoins.wallet.config.WalletAppConfig
|
||||
import ujson._
|
||||
|
||||
|
15
build.sbt
15
build.sbt
@ -80,7 +80,8 @@ lazy val `bitcoin-s` = project
|
||||
appCommonsTest,
|
||||
testkit,
|
||||
zmq,
|
||||
oracleServer
|
||||
oracleServer,
|
||||
serverRoutes
|
||||
)
|
||||
.dependsOn(
|
||||
secp256k1jni,
|
||||
@ -117,7 +118,8 @@ lazy val `bitcoin-s` = project
|
||||
appCommonsTest,
|
||||
testkit,
|
||||
zmq,
|
||||
oracleServer
|
||||
oracleServer,
|
||||
serverRoutes
|
||||
)
|
||||
.settings(CommonSettings.settings: _*)
|
||||
// unidoc aggregates Scaladocs for all subprojects into one big doc
|
||||
@ -281,13 +283,20 @@ lazy val oracleServer = project
|
||||
.settings(CommonSettings.prodSettings: _*)
|
||||
.dependsOn(
|
||||
dlcOracle,
|
||||
appServer
|
||||
serverRoutes
|
||||
)
|
||||
|
||||
lazy val serverRoutes = project
|
||||
.in(file("app/server-routes"))
|
||||
.settings(CommonSettings.prodSettings: _*)
|
||||
.settings(libraryDependencies ++= Deps.serverRoutes)
|
||||
.dependsOn(appCommons, dbCommons)
|
||||
|
||||
lazy val appServer = project
|
||||
.in(file("app/server"))
|
||||
.settings(CommonSettings.prodSettings: _*)
|
||||
.dependsOn(
|
||||
serverRoutes,
|
||||
appCommons,
|
||||
node,
|
||||
chain,
|
||||
|
@ -430,4 +430,11 @@ object Deps {
|
||||
Compile.newMicroJson,
|
||||
Compile.logback
|
||||
)
|
||||
|
||||
val serverRoutes = List(
|
||||
Compile.akkaHttp,
|
||||
Compile.akkaActor,
|
||||
Compile.akkaSlf4j,
|
||||
Compile.akkaStream
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user