Remove oracle explorer client (#5308)

* Remove oracle explorer client

* Remove doc, remove ci flow
This commit is contained in:
Chris Stewart 2023-11-22 10:27:29 -06:00 committed by GitHub
parent 4913b12431
commit c0e8d376eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1 additions and 515 deletions

View File

@ -30,4 +30,4 @@ jobs:
~/.bitcoin-s/binaries
key: ${{ runner.os }}-cache
- name: run tests
run: sbt coverage keyManagerTest/test keyManager/coverageReport keyManager/coverageAggregate keyManager/coveralls feeProviderTest/test walletTest/test dlcWalletTest/test wallet/coverageReport wallet/coverageAggregate wallet/coveralls dlcOracleTest/test asyncUtilsTestJVM/test oracleExplorerClient/test dlcOracle/coverageReport dlcOracle/coverageAggregate dlcOracle/coveralls
run: sbt coverage keyManagerTest/test keyManager/coverageReport keyManager/coverageAggregate keyManager/coveralls feeProviderTest/test walletTest/test dlcWalletTest/test wallet/coverageReport wallet/coverageAggregate wallet/coveralls dlcOracleTest/test asyncUtilsTestJVM/test dlcOracle/coverageReport dlcOracle/coverageAggregate dlcOracle/coveralls

View File

@ -224,7 +224,6 @@ lazy val `bitcoin-s` = project
testkitCoreJS,
testkit,
zmq,
oracleExplorerClient,
oracleServer,
oracleServerTest,
serverRoutes,
@ -281,7 +280,6 @@ lazy val `bitcoin-s` = project
appCommonsTest,
testkit,
zmq,
oracleExplorerClient,
oracleServer,
oracleServerTest,
serverRoutes,
@ -705,7 +703,6 @@ lazy val docs = project
cryptoJVM,
coreJVM,
dbCommons,
oracleExplorerClient,
feeProvider,
dlcOracle,
eclairRpc,
@ -806,15 +803,6 @@ lazy val dlcOracleTest = project
)
.dependsOn(coreJVM % testAndCompile, dlcOracle, testkit)
lazy val oracleExplorerClient = project
.in(file("oracle-explorer-client"))
.settings(CommonSettings.settings: _*)
.settings(
name := "bitcoin-s-oracle-explorer-client",
libraryDependencies ++= Deps.oracleExplorerClient
)
.dependsOn(coreJVM, appCommons, tor, testkit % "test->test")
lazy val scripts = project
.in(file("app/scripts"))
.settings(CommonSettings.settings: _*)

View File

@ -1,72 +0,0 @@
---
id: oracle-explorer-client
title: Oracle Explorer Client
---
[Suredbits offers a tool called an Oracle Explorer](https://oracle.suredbits.com) for oracles to post their
announcements and attestments at a later time.
Bitcoin-s provides an open source oracle explorer client for
interacting with the oracle explorer.
### Environments
There are 2 live environments that can be used with the explorer client
1. ExplorerEnv.Production
2. ExplorerEnv.Test
As the names indicate, one references the [production oracle explorer](https://oracle.suredbits.com)
while the other references the [test environment](https://test.oracle.suredbits.com)
```scala mdoc:invisible
import akka.actor.ActorSystem
import org.bitcoins.explorer.client._
import org.bitcoins.commons.jsonmodels._
import org.bitcoins.explorer.model._
import org.bitcoins.core.protocol.tlv.{OracleAnnouncementV0TLV,OracleAttestmentV0TLV}
import scala.concurrent.Future
```
```scala mdoc:compile-only
implicit val system = ActorSystem("explorer-client-actor-system")
//use test environment for this little example
val env = ExplorerEnv.Test
val explorerClient = SbExplorerClient(env, proxyParams = None)
//list all announcemnts on the explorer
val announcementsF: Future[Vector[SbAnnouncementEvent]] = explorerClient.listAnnouncements()
//example announcement taken from
//https://oracle.suredbits.com/event/e0a5624edbc854120982165b0eef53f0777a49febd79a0c21bf75e5582021e33
val announcementHex = "fdd824c8bf634b2d76f6d8c6499aa977a7b0ae2b84bc206d800f8448e46d63d6ca31778ddb023e39df098c7e109b3d6ee7273d18be62e10f8481dae6531dbe3e0647f6e95d1bcfab252c6dd9edd7aea4c5eeeef138f7ff7346061ea40143a9f5ae80baa9fdd82264000190ef605e3450e16b47745e7a33e26ac9437f6ec2ed660d829a064dceee3699c8605fc700fdd806270005076e67616e6e6f75066d696f63696304647261770a6e6f2d636f6e74657374056f74686572124d696f6369632076204e67616e6e6f752032"
val announcement = OracleAnnouncementV0TLV.fromHex(announcementHex)
//you can query by announcement
val announcementF: Future[SbAnnouncementEvent] = explorerClient.getAnnouncement(announcement)
//or query by hash
val sameAnnouncementF: Future[SbAnnouncementEvent] = explorerClient.getAnnouncement(announcement.sha256)
//you can post an announcement to the oracle explorer
val oracleName = "Chris_Stewart_5"
val description = "2021-03-24-sunny-in-chicago"
val uriOpt = Some("https://twitter.com/Chris_Stewart_5")
val sbAnnouncement = CreateAnnouncementExplorer(announcement, oracleName, description, uriOpt)
val createdF = explorerClient.createAnnouncement(sbAnnouncement)
//and then you can follow up and post the attestations
val attestationsHex =
"fdd868821b323032312d30332d32342d73756e6e792d696e2d6368696361676f1d5dcdba2e64cb116cc0c375a0856298f0058b778f46bfe625ac6576204889e40001efdf735567ae0a00a515e313d20029de5d7525da7b8367bc843d28b672d4db4db5de4dbff689f3b742be634a9c92c615dbcf2eadbdd470f514b1ac250a30db6d03594553"
val attestations = OracleAttestmentV0TLV.fromHex(attestationsHex)
val announcementHash = announcement.sha256
val sbAttestations = CreateAttestations(announcementHash, attestations)
val createdAttestationsF = explorerClient.createAttestations(sbAttestations)
```

View File

@ -1,182 +0,0 @@
package org.bitcoins.explorer.client
import akka.actor.ActorSystem
import akka.http.scaladsl.model._
import akka.http.scaladsl.{Http, HttpExt}
import akka.util.ByteString
import org.bitcoins.commons.jsonmodels.ExplorerEnv
import org.bitcoins.core.api.tor.Socks5ProxyParams
import org.bitcoins.core.protocol.tlv.OracleAnnouncementTLV
import org.bitcoins.core.util.FutureUtil
import org.bitcoins.crypto.{SchnorrPublicKey, Sha256Digest}
import org.bitcoins.explorer.model.{
CreateAnnouncementExplorer,
CreateAttestations,
Oracle,
SbAnnouncementEvent
}
import org.bitcoins.explorer.picklers.ExplorerPicklers
import org.bitcoins.tor.{Socks5ClientTransport}
import play.api.libs.json.{
JsArray,
JsBoolean,
JsError,
JsNull,
JsNumber,
JsObject,
JsString,
JsSuccess,
JsValue,
Json
}
import java.net.URI
import scala.concurrent.Future
/** A class that implements the Suredbits oracle explorer API */
case class SbExplorerClient(
env: ExplorerEnv,
proxyParams: Option[Socks5ProxyParams])(implicit system: ActorSystem) {
import ExplorerPicklers._
import system.dispatcher
private val httpClient: HttpExt = Http(system)
private val baseUri: String = proxyParams match {
case Some(_) => env.torBaseUri
case None => env.baseUri
}
private val httpConnectionPoolSettings =
Socks5ClientTransport.createConnectionPoolSettings(new URI(baseUri),
proxyParams)
/** Lists all events on oracle explorer
* @see https://gist.github.com/Christewart/a9e55d9ba582ac9a5ceffa96db9d7e1f#list-all-events
* @return
*/
def listAnnouncements(): Future[Vector[SbAnnouncementEvent]] = {
val uri = Uri(baseUri + "announcements")
val httpReq = HttpRequest(uri = uri)
val responseF = sendRequest(httpReq)
responseF.flatMap { response =>
val result = response.validate[Vector[SbAnnouncementEvent]]
result match {
case success: JsSuccess[Vector[SbAnnouncementEvent]] =>
Future.successful(success.value)
case err: JsError =>
Future.failed(
new RuntimeException(
s"Failed to parse response for listAnnouncements, err=$err"))
}
}
}
/** Gets an announcement from the oracle explorer
* @see https://gist.github.com/Christewart/a9e55d9ba582ac9a5ceffa96db9d7e1f#get-event
*/
def getAnnouncement(
announcement: OracleAnnouncementTLV): Future[SbAnnouncementEvent] = {
getAnnouncement(announcement.sha256)
}
/** Gets an announcement from the oracle explorer
* @see https://gist.github.com/Christewart/a9e55d9ba582ac9a5ceffa96db9d7e1f#get-event
*/
def getAnnouncement(
announcementHash: Sha256Digest): Future[SbAnnouncementEvent] = {
val uri = Uri(baseUri + s"announcements/${announcementHash.hex}")
val httpReq = HttpRequest(uri = uri)
val responseF = sendRequest(httpReq)
responseF.flatMap { response =>
val result = response.validate[SbAnnouncementEvent]
result match {
case success: JsSuccess[SbAnnouncementEvent] =>
Future.successful(success.value)
case err: JsError =>
Future.failed(
new RuntimeException(
s"Failed to parse response for getAnnouncement, err=$err"))
}
}
}
/** Creates an announcement on the oracle explorer
* @see https://gist.github.com/Christewart/a9e55d9ba582ac9a5ceffa96db9d7e1f#create-an-event
*/
def createAnnouncement(
oracleEventExplorer: CreateAnnouncementExplorer): Future[Unit] = {
val uri = Uri(baseUri + s"announcements")
val string = oracleEventExplorer.toString
val httpReq =
HttpRequest(
uri = uri,
method = HttpMethods.POST,
entity =
HttpEntity(ContentTypes.`application/x-www-form-urlencoded`, string))
val responseF = sendRequest(httpReq)
responseF.map(_ => ())
}
/** Creates an attestation for an announcement on the oracle explorer
* @see https://gist.github.com/Christewart/a9e55d9ba582ac9a5ceffa96db9d7e1f#create-an-events-attestation
*/
def createAttestations(attestations: CreateAttestations): Future[Unit] = {
val uri = Uri(
baseUri + s"announcements/${attestations.announcementHash.hex}/attestations")
val string = attestations.toString
val httpReq =
HttpRequest(
uri = uri,
method = HttpMethods.POST,
entity =
HttpEntity(ContentTypes.`application/x-www-form-urlencoded`, string))
val responseF = sendRequest(httpReq)
responseF.map(_ => ())
}
def getOracleName(pubkey: SchnorrPublicKey): Future[Option[String]] = {
val uri = Uri(baseUri + s"oracle/${pubkey.hex}")
val httpReq = HttpRequest(uri = uri)
val responseF = sendRequest(httpReq)
responseF.flatMap { response =>
val result = response.validate[Oracle]
result match {
case success: JsSuccess[Oracle] =>
Future.successful(Some(success.value.oracleName))
case _: JsError => FutureUtil.none
}
}
}
private def sendRequest(httpReq: HttpRequest): Future[JsValue] = {
val responsePayloadF: Future[String] = {
httpClient
.singleRequest(httpReq, settings = httpConnectionPoolSettings)
.flatMap(response =>
response.entity.dataBytes
.runFold(ByteString.empty)(_ ++ _)
.map(payload => payload.decodeString(ByteString.UTF_8)))
}
val responseJsonF: Future[JsValue] = responsePayloadF.map(Json.parse)
responseJsonF.flatMap {
case x @ (_: JsNumber | _: JsString | _: JsArray | JsNull |
_: JsBoolean) =>
Future.failed(
new RuntimeException(
s"Incorrect formatted response from oracle explorer, got=$x"))
case obj: JsObject =>
val map = obj.value
val error = map.get("error")
val result = map.get("result")
if (error.get != JsNull) {
Future.failed(
new RuntimeException(
s"Error returned by oracle explroer, err=${error}"))
} else {
Future.successful(result.get)
}
}
}
}

View File

@ -1,21 +0,0 @@
package org.bitcoins.explorer.model
import org.bitcoins.core.protocol.tlv.OracleAnnouncementV0TLV
case class CreateAnnouncementExplorer(
oracleAnnouncementV0: OracleAnnouncementV0TLV,
oracleName: String,
description: String,
eventURI: Option[String]) {
override def toString: String = {
val base =
s"oracleAnnouncementV0=${oracleAnnouncementV0.hex}&description=$description&oracleName=$oracleName"
eventURI match {
case None => base
case Some(uri) =>
val uriString = s"&uri=$uri"
base + uriString
}
}
}

View File

@ -1,22 +0,0 @@
package org.bitcoins.explorer.model
import org.bitcoins.core.protocol.tlv._
import org.bitcoins.crypto.Sha256Digest
case class CreateAttestations(
announcementHash: Sha256Digest,
attestment: OracleAttestmentV0TLV) {
override def toString: String = {
s"attestations=${attestment.hex}"
}
}
object CreateAttestations {
def apply(
announcement: OracleAnnouncementTLV,
attestment: OracleAttestmentV0TLV): CreateAttestations = {
CreateAttestations(announcement.sha256, attestment)
}
}

View File

@ -1,5 +0,0 @@
package org.bitcoins.explorer.model
import org.bitcoins.crypto.SchnorrPublicKey
case class Oracle(pubkey: SchnorrPublicKey, oracleName: String)

View File

@ -1,16 +0,0 @@
package org.bitcoins.explorer.model
import org.bitcoins.core.protocol.tlv.{
OracleAnnouncementV0TLV,
OracleAttestmentV0TLV
}
import org.bitcoins.crypto.Sha256Digest
case class SbAnnouncementEvent(
id: Sha256Digest,
oracleName: String,
description: String,
uri: Option[String],
announcement: OracleAnnouncementV0TLV,
attestations: Option[OracleAttestmentV0TLV],
outcome: Option[String])

View File

@ -1,12 +0,0 @@
package org.bitcoins.explorer.picklers
import org.bitcoins.explorer.model._
import org.bitcoins.commons.serializers.JsonReaders._
import play.api.libs.json.{Json, Reads}
object ExplorerPicklers {
implicit val explorerEventRW: Reads[SbAnnouncementEvent] =
Json.reads[SbAnnouncementEvent]
implicit val oracleRW: Reads[Oracle] = Json.reads[Oracle]
}

View File

@ -1,114 +0,0 @@
package org.bitcoins.explorer.client
import org.bitcoins.commons.jsonmodels.ExplorerEnv
import org.bitcoins.core.api.tor.Socks5ProxyParams
import org.bitcoins.core.protocol.tlv.{
OracleAnnouncementV0TLV,
OracleAttestmentV0TLV
}
import org.bitcoins.crypto.Sha256Digest
import org.bitcoins.explorer.model.{
CreateAnnouncementExplorer,
CreateAttestations,
SbAnnouncementEvent
}
import org.bitcoins.testkit.util.BitcoinSAsyncTest
import scala.concurrent.Future
class SbExplorerClientTest extends BitcoinSAsyncTest {
behavior of "SbExplorerClient"
private val proxyParams = Option.empty[Socks5ProxyParams]
private val explorerClient =
SbExplorerClient(ExplorerEnv.Production, proxyParams)
//https://test.oracle.suredbits.com/event/57505dcdfe8746d9adf3454df538244a425f302c07642d9dc4a4f635fbf08d30
private val announcementHex: String =
"fdd824b33cbc4081b947ea9d05e616b010b563bfdbc42a2d20effa6f169f8e4be732b10d5461fa84b5739876a0c8a7bdb717040b8ee5907fe7e60694199ba948ecd505b01d5dcdba2e64cb116cc0c375a0856298f0058b778f46bfe625ac6576204889e4fdd8224f0001efdf735567ae0a00a515e313d20029de5d7525da7b8367bc843d28b672d4db4d605bd280fdd80609000203594553024e4f1b323032312d30332d32342d73756e6e792d696e2d6368696361676f"
private val announcement: OracleAnnouncementV0TLV =
OracleAnnouncementV0TLV.fromHex(announcementHex)
it must "list events" in {
val eventsF: Future[Vector[SbAnnouncementEvent]] =
explorerClient.listAnnouncements()
for {
events <- eventsF
} yield {
assert(events.nonEmpty)
}
}
it must "get an event" in {
val hash = announcement.sha256
val eventsF = explorerClient.getAnnouncement(hash)
for {
event <- eventsF
} yield {
assert(event.announcement.sha256 == hash)
}
}
it must "get an oracle name" in {
val key = announcement.publicKey
for {
name <- explorerClient.getOracleName(key)
} yield {
assert(name.contains("Chris_Stewart_5"))
}
}
it must "return failure from get an event if the event DNE" in {
val hash = Sha256Digest.empty
recoverToSucceededIf[RuntimeException] {
explorerClient.getAnnouncement(hash)
}
}
it must "create an event on the oracle explorer and then get that event" ignore {
val oracleName = "Chris_Stewart_5"
val description = "2021-03-24-sunny-in-chicago"
val uriOpt = Some("https://twitter.com/Chris_Stewart_5")
val event =
CreateAnnouncementExplorer(announcement, oracleName, description, uriOpt)
val createdF = explorerClient.createAnnouncement(event)
for {
_ <- createdF
event <- explorerClient.getAnnouncement(event.oracleAnnouncementV0.sha256)
} yield {
assert(event.announcement == announcement)
assert(event.attestations.isEmpty)
assert(event.uri == uriOpt)
assert(event.oracleName == oracleName)
assert(event.description == description)
}
}
it must "post attestations for an event to the oracle explorer" ignore {
//the announcement is posted in the test case above
//which means the test case above must be run before this test case
val attestationsHex =
"fdd868821b323032312d30332d32342d73756e6e792d696e2d6368696361676f1d5dcdba2e64cb116cc0c375a0856298f0058b778f46bfe625ac6576204889e40001efdf735567ae0a00a515e313d20029de5d7525da7b8367bc843d28b672d4db4db5de4dbff689f3b742be634a9c92c615dbcf2eadbdd470f514b1ac250a30db6d03594553"
val attestations = OracleAttestmentV0TLV.fromHex(attestationsHex)
val announcementHash = announcement.sha256
val create = CreateAttestations(announcementHash, attestations)
val createdF = explorerClient.createAttestations(create)
for {
_ <- createdF
//now we must have the attesations
event <- explorerClient.getAnnouncement(announcementHash)
} yield {
assert(event.attestations.isDefined)
assert(event.attestations.get == attestations)
}
}
}

View File

@ -1,22 +0,0 @@
package org.bitcoins.explorer.env
import org.bitcoins.commons.jsonmodels.ExplorerEnv._
import org.bitcoins.commons.jsonmodels.ExplorerEnv
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
class ExplorerEnvTest extends BitcoinSUnitTest {
behavior of "ExplorerEnv"
it must "have all base uris envs end with a '/'" in {
ExplorerEnv.all.foreach { e =>
assert(e.baseUri.last == '/')
}
}
it must "correctly parse from string" in {
assert(ExplorerEnv.fromString("Production") == Production)
assert(ExplorerEnv.fromString("Test") == Test)
assert(ExplorerEnv.fromString("Local") == Local)
}
}

View File

@ -1,29 +0,0 @@
package org.bitcoins.explorer.model
import org.bitcoins.core.protocol.tlv.OracleAnnouncementV0TLV
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
class SbOracleEventExplorerTest extends BitcoinSUnitTest {
behavior of "SbOracleEvent"
it must "encode the event to POST for a form" in {
val announcementHex =
"fdd824b33cbc4081b947ea9d05e616b010b563bfdbc42a2d20effa6f169f8e4be732b10d5461fa84b5739876a0c8a7bdb717040b8ee5907fe7e60694199ba948ecd505b01d5dcdba2e64cb116cc0c375a0856298f0058b778f46bfe625ac6576204889e4fdd8224f0001efdf735567ae0a00a515e313d20029de5d7525da7b8367bc843d28b672d4db4d605bd280fdd80609000203594553024e4f1b323032312d30332d32342d73756e6e792d696e2d6368696361676f"
val announcement = OracleAnnouncementV0TLV.fromHex(announcementHex)
val oracleName = "Chris_Stewart_5"
val description = "2021-03-24-sunny-in-chicago"
val uriOpt = Some("https://twitter.com/Chris_Stewart_5")
val event =
CreateAnnouncementExplorer(announcement, oracleName, description, uriOpt)
val expected = s"oracleAnnouncementV0=${announcementHex}&" +
s"description=$description&" +
s"oracleName=${oracleName}&" +
s"uri=${uriOpt.get}"
assert(event.toString == expected)
}
}

View File

@ -687,11 +687,4 @@ object Deps {
Compile.slf4j,
Compile.grizzledSlf4j
)
val oracleExplorerClient = Vector(
Compile.akkaActor,
Compile.akkaHttp,
Compile.akkaStream,
Compile.playJson
)
}