Skip to content

Commit

Permalink
TSDK-733 Add tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
mundacho committed Feb 2, 2024
1 parent 316a078 commit b6e3544
Show file tree
Hide file tree
Showing 11 changed files with 239 additions and 96 deletions.
77 changes: 49 additions & 28 deletions topl-btc-bridge/src/main/scala/co/topl/bridge/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,32 @@ import cats.effect.kernel.Resource
import co.topl.bridge.BridgeParamsDescriptor
import co.topl.bridge.ServerConfig
import co.topl.bridge.ToplBTCBridgeParamConfig
import co.topl.bridge.services.ConfirmRedemptionModule
import co.topl.bridge.services.SessionManagerAlgebra
import co.topl.bridge.services.SessionManagerImpl
import co.topl.bridge.services.StartSessionModule
import co.topl.bridge.controllers.ConfirmRedemptionController
import co.topl.bridge.controllers.StartSessionController
import co.topl.bridge.managers.BTCWalletAlgebra
import co.topl.bridge.managers.BTCWalletImpl
import co.topl.bridge.managers.SessionManagerAlgebra
import co.topl.bridge.managers.SessionManagerImpl
import co.topl.shared.BitcoinNetworkIdentifiers
import co.topl.shared.StartSessionRequest
import co.topl.shared.utils.KeyGenerationUtils
import io.circe.generic.auto._
import org.http4s.HttpRoutes
import org.http4s._
import org.http4s.circe._
import org.http4s.dsl.io._
import org.http4s.ember.server.EmberServerBuilder
import org.http4s.server.Router
import org.http4s.server.staticcontent.resourceServiceBuilder
import scopt.OParser

import java.util.concurrent.ConcurrentHashMap
import co.topl.shared.utils.KeyGenerationUtils
import co.topl.bridge.services.BTCWalletImpl
import co.topl.bridge.services.BTCWalletAlgebra
import co.topl.shared.ConfirmRedemptionRequest

object Main extends IOApp with BridgeParamsDescriptor {

object Main
extends IOApp
with BridgeParamsDescriptor
with StartSessionModule
with ConfirmRedemptionModule {
import StartSessionController._
import ConfirmRedemptionController._

def apiServices(
sessionManager: SessionManagerAlgebra[IO],
Expand All @@ -39,28 +42,42 @@ object Main
btcNetwork: BitcoinNetworkIdentifiers
) = HttpRoutes.of[IO] {
case req @ POST -> Root / "start-session" =>
startSession(
req,
pegInWalletManager,
sessionManager,
btcNetwork
)
implicit val startSessionRequestDecoder
: EntityDecoder[IO, StartSessionRequest] =
jsonOf[IO, StartSessionRequest]
import io.circe.syntax._
for {
x <- req.as[StartSessionRequest]
res <- startSession(
x,
pegInWalletManager,
sessionManager,
btcNetwork
)
resp <- Ok(res.asJson)
} yield resp
case req @ POST -> Root / "confirm-redemption" =>
confirmRedemption(
req,
pegInWalletManager,
walletManager,
sessionManager
)
implicit val confirmRedemptionRequestDecoder
: EntityDecoder[IO, ConfirmRedemptionRequest] =
jsonOf[IO, ConfirmRedemptionRequest]
for {
x <- req.as[ConfirmRedemptionRequest]
res <- confirmRedemption(
x,
pegInWalletManager,
walletManager,
sessionManager
)
} yield res
}

override def run(args: List[String]): IO[ExitCode] = {
OParser.parse(parser, args, ToplBTCBridgeParamConfig()) match {
case Some(config) =>
runWithArgs(config)
case None =>
println("Invalid arguments")
IO(ExitCode.Error)
IO.consoleForIO.errorln("Invalid arguments") *>
IO(ExitCode.Error)
}
}

Expand Down Expand Up @@ -95,11 +112,15 @@ object Main
params.walletPassword
)
)(_ => IO.unit)
pegInWalletManager <- Resource.make(
BTCWalletImpl.make[IO](pegInKm)
)(_ => IO.unit)
walletManager <- Resource.make(
BTCWalletImpl.make[IO](walletKm)
)(_ => IO.unit)
app = {
val sessionManager =
SessionManagerImpl.make[IO](new ConcurrentHashMap())
val pegInWalletManager = BTCWalletImpl.make[IO](pegInKm)
val walletManager = BTCWalletImpl.make[IO](walletKm)
val router = Router.define(
"/" -> apiServices(
sessionManager,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package co.topl.bridge.services
package co.topl.bridge.controllers

import cats.effect.kernel.Async
import co.topl.bridge.BitcoinUtils
import co.topl.bridge.services.StartSessionModule
import cats.effect.kernel.Sync
import co.topl.bridge.managers.BTCWalletAlgebra
import co.topl.bridge.managers.SessionManagerAlgebra
import co.topl.bridge.utils.BitcoinUtils
import co.topl.shared.ConfirmRedemptionRequest
import co.topl.shared.ConfirmRedemptionResponse
import io.circe.generic.auto._
Expand All @@ -14,29 +16,22 @@ import org.bitcoins.core.protocol.transaction.WitnessTransaction
import org.bitcoins.core.script.constant.OP_0
import org.bitcoins.core.script.constant.ScriptConstant
import org.bitcoins.crypto._
import org.http4s._
import org.http4s.circe._
import scodec.bits.ByteVector

trait ConfirmRedemptionModule {

self: StartSessionModule =>
object ConfirmRedemptionController {

def confirmRedemption[F[_]: Async](
req: Request[F],
req: ConfirmRedemptionRequest,
pegInWalletManager: BTCWalletAlgebra[F],
walletManager: BTCWalletAlgebra[F],
sessionManager: SessionManagerAlgebra[F]
) = {
implicit val confirmRedemptionRequestDecoder
: EntityDecoder[F, ConfirmRedemptionRequest] =
jsonOf[F, ConfirmRedemptionRequest]
import io.circe.syntax._
import cats.implicits._
val dsl = org.http4s.dsl.Http4sDsl[F]
import dsl._
(for {
req <- req.as[ConfirmRedemptionRequest]
sessionInfo <- sessionManager.getSession(req.sessionID)
nextPubKey <- walletManager.getCurrentPubKey()
tx = BitcoinUtils.createRedeemingTx(
Expand Down Expand Up @@ -80,8 +75,8 @@ trait ConfirmRedemptionModule {
).asJson
)
} yield resp).handleErrorWith(e => {
e.printStackTrace()
BadRequest("Error")
Sync[F].delay(e.printStackTrace()) *>
BadRequest("Error")
})
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package co.topl.bridge.services
package co.topl.bridge.controllers

import cats.effect.kernel.Async
import co.topl.bridge.BitcoinUtils
import co.topl.bridge.managers.BTCWalletAlgebra
import co.topl.bridge.managers.SessionInfo
import co.topl.bridge.managers.SessionManagerAlgebra
import co.topl.bridge.utils.BitcoinUtils
import co.topl.shared.BitcoinNetworkIdentifiers
import co.topl.shared.StartSessionRequest
import co.topl.shared.StartSessionResponse
import io.circe.generic.auto._
import org.bitcoins.core.protocol.Bech32Address
import org.bitcoins.core.protocol.script.WitnessScriptPubKey
import org.bitcoins.core.script.constant.OP_0
Expand All @@ -14,22 +16,11 @@ import org.bitcoins.core.util.BitcoinScriptUtil
import org.bitcoins.core.util.BytesUtil
import org.bitcoins.crypto.ECPublicKey
import org.bitcoins.crypto._
import org.http4s._
import org.http4s.circe._
import scodec.bits.ByteVector

case class SessionInfo(
bridgePKey: String,
currentWalletIdx: Int,
userPKey: String,
secretHash: String,
scriptAsm: String,
address: String
)
object StartSessionController {

trait StartSessionModule {

def createSessionInfo(
private def createSessionInfo(
currentWalletIdx: Int,
sha256: String,
userPKey: String,
Expand Down Expand Up @@ -69,20 +60,13 @@ trait StartSessionModule {
}

def startSession[F[_]: Async](
request: Request[F],
req: StartSessionRequest,
pegInWalletManager: BTCWalletAlgebra[F],
sessionManager: SessionManagerAlgebra[F],
btcNetwork: BitcoinNetworkIdentifiers
) = {
implicit val startSessionRequestDecoder
: EntityDecoder[F, StartSessionRequest] =
jsonOf[F, StartSessionRequest]
import io.circe.syntax._
import cats.implicits._
val dsl = org.http4s.dsl.Http4sDsl[F]
import dsl._
(for {
req <- request.as[StartSessionRequest]
idxAndnewKey <- pegInWalletManager.getCurrentPubKeyAndPrepareNext()
(idx, newKey) = idxAndnewKey
sessionInfo = createSessionInfo(
Expand All @@ -93,18 +77,12 @@ trait StartSessionModule {
btcNetwork
)
sessionId <- sessionManager.createNewSession(sessionInfo)
resp <- Ok(
StartSessionResponse(
sessionId,
sessionInfo.scriptAsm,
sessionInfo.address,
BitcoinUtils.createDescriptor(newKey.hex, req.pkey, req.sha256)
).asJson
)
} yield resp).handleErrorWith(e => {
e.printStackTrace()
BadRequest("Error")
})
} yield StartSessionResponse(
sessionId,
sessionInfo.scriptAsm,
sessionInfo.address,
BitcoinUtils.createDescriptor(newKey.hex, req.pkey, req.sha256)
))
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
package co.topl.bridge.services
package co.topl.bridge.managers

import cats.effect.kernel.Sync

import java.util.UUID
import java.util.concurrent.ConcurrentMap


case class SessionInfo(
bridgePKey: String,
currentWalletIdx: Int,
userPKey: String,
secretHash: String,
scriptAsm: String,
address: String
)

trait SessionManagerAlgebra[F[_]] {
def createNewSession(
sessionInfo: SessionInfo
Expand All @@ -26,7 +36,6 @@ object SessionManagerImpl {
for {
sessionId <- Sync[F].delay(UUID.randomUUID().toString)
_ <- Sync[F].delay(map.put(sessionId, sessionInfo))
_ = println("map: " + map)
} yield sessionId
}

Expand All @@ -35,8 +44,6 @@ object SessionManagerImpl {
): F[SessionInfo] = {
Sync[F].fromOption(
{
println("map: " + map)
println("sessionId: " + sessionId)
Option(map.get(sessionId))
},
new IllegalArgumentException("Invalid session ID")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package co.topl.bridge.services
package co.topl.bridge.managers

import cats.effect.kernel.Ref
import cats.effect.kernel.Sync
Expand All @@ -20,30 +20,32 @@ object BTCWalletImpl {

def make[F[_]: Sync](
km: BIP39KeyManager
): BTCWalletAlgebra[F] = {
): F[BTCWalletAlgebra[F]] = {
import cats.implicits._

val currentIdxRef = Ref[F].of(0)
new BTCWalletAlgebra[F] {
for {
currentIdx <- Ref[F].of(0)
} yield new BTCWalletAlgebra[F] {
override def getCurrentPubKeyAndPrepareNext(): F[(Int, ECPublicKey)] = {
import cats.implicits._
for {
currentIdx <- currentIdxRef
idx <- currentIdx.getAndUpdate(_ + 1)
nextIdx <- currentIdx.get
_ = println("idx: " + nextIdx)
pubKey <- KeyGenerationUtils.generateKey(km, idx)
} yield (idx, pubKey)
}

override def getCurrentPubKey(): F[ECPublicKey] = {
import cats.implicits._
for {
currentIdx <- currentIdxRef
idx <- currentIdx.get
pubKey <- KeyGenerationUtils.generateKey(km, idx)
} yield pubKey
}

override def signForIdx(idx: Int, txBytes: ByteVector): F[ECDigitalSignature] = {
import cats.implicits._
override def signForIdx(
idx: Int,
txBytes: ByteVector
): F[ECDigitalSignature] = {
for {
signed <- Sync[F].delay(
km.toSign(HDPath.fromString("m/84'/1'/0'/0/" + idx))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package co.topl.bridge
package co.topl.bridge.utils

import org.bitcoins.core.currency.CurrencyUnit
import org.bitcoins.core.number.Int32
Expand Down
1 change: 1 addition & 0 deletions topl-btc-bridge/src/test/resources/wallet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"iv":"511f56031deab951ece6239bff2e4d67","cipherText":"a0e23abf6bba12a1bb9722d1a70abb5f4e1d633997edb9efa2e0528e483d4b8f65f28e0ad07f68e1fb7ec9e7b77f4fb3763d073aad87b9736766eec53b82e025bf3e1d27d3e2336e9ca0ad25784b5c9be4ca1b5bbd17b80c7416f4b281b29c3166496e65db51b5854c661e149d4c651c9446925c736cb1c52eb21dd9d53a3b6c74ff8ec79606889a1c2f1f5348c7d2ca600e970c401c","salt":"7d9f4d1355326c120f483f76fe7100daec637b5a279ae7185d0ec353345ec475","creationTime":1706812586,"backupTime":null,"imported":false}

0 comments on commit b6e3544

Please sign in to comment.