Add signed outcome to getevent rpc, fix other small api bugs (#2757)

* Add signed outcome to get event rpc, fix other small api bugs

* Create separate type for decomp DLCAttestationType

* Add DLCOutcomeType to Oracle Event

* Calculate dlcOutcome, add invariant

* Fix test
This commit is contained in:
benthecarman 2021-03-08 10:55:47 -06:00 committed by GitHub
parent aed21f02c7
commit 4bf4f0a027
13 changed files with 135 additions and 48 deletions

View file

@ -416,6 +416,8 @@ object Picklers {
val numericOracles =
oracles.map(_.asInstanceOf[NumericSingleOracleInfo])
NumericOracleOutcome(numericOracles.zip(numericOutcomes))
case signed: SignedNumericOutcome =>
throw new IllegalArgumentException(s"Unexpected outcome $signed")
}
state match {

View file

@ -1053,7 +1053,7 @@ object ConsoleCli {
.text(s"Get oracle's staking address"),
cmd("listevents")
.action((_, conf) => conf.copy(command = ListEvents))
.text(s"Lists all event announcements"),
.text(s"Lists all event names"),
cmd("createenumevent")
.action((_, conf) =>
conf.copy(command = CreateEnumEvent("", new Date(), Seq.empty)))

View file

@ -10,15 +10,11 @@ import org.bitcoins.core.protocol.Bech32Address
import org.bitcoins.core.protocol.dlc.SigningVersion
import org.bitcoins.core.protocol.tlv.{
EnumEventDescriptorV0TLV,
NormalizedString,
OracleAnnouncementV0TLV,
OracleAttestmentV0TLV
}
import org.bitcoins.crypto.{
ECPublicKey,
FieldElement,
SchnorrDigitalSignature,
SchnorrPublicKey
}
import org.bitcoins.crypto._
import org.bitcoins.dlc.oracle.config.DLCOracleAppConfig
import org.bitcoins.server.routes.ServerCommand
import org.bitcoins.testkit.BitcoinSTestAppConfig
@ -44,18 +40,28 @@ class OracleRoutesSpec
val testAddressStr = "bc1qvrctqwa6g70z5vtxsyft7xvsyyt749trlm80al"
val testAddress: Bech32Address = Bech32Address.fromString(testAddressStr)
val dummyKey: ECPublicKey = ECPublicKey.freshPublicKey
val kVal: ECPrivateKey = ECPrivateKey.freshPrivateKey
val dummyPrivKey: ECPrivateKey = ECPrivateKey.freshPrivateKey
val dummyKey: ECPublicKey = dummyPrivKey.publicKey
val outcome: NormalizedString = EnumEventDescriptorV0TLV.dummy.outcomes.head
val hash: Sha256Digest = CryptoUtil.sha256DLCAttestation(outcome)
val sig: SchnorrDigitalSignature =
dummyPrivKey.schnorrSignWithNonce(hash.bytes, kVal)
val dummyEventDb: EventDb = EventDb(
nonce = dummyKey.schnorrNonce,
nonce = kVal.schnorrNonce,
pubkey = dummyKey.schnorrPublicKey,
nonceIndex = 0,
eventName = "id",
numOutcomes = 2,
signingVersion = SigningVersion.latest,
maturationTime = Instant.ofEpochSecond(0),
attestationOpt = Some(FieldElement.one),
outcomeOpt = Some("outcome"),
attestationOpt = Some(sig.sig),
outcomeOpt = Some(outcome),
announcementSignature = SchnorrDigitalSignature(
"1efe41fa42ea1dcd103a0251929dd2b192d2daece8a4ce4d81f68a183b750d92d6f02d796965dc79adf4e7786e08f861a1ecc897afbba2dab9cff6eb0a81937e"),
eventDescriptorTLV = EnumEventDescriptorV0TLV.dummy
@ -113,8 +119,8 @@ class OracleRoutesSpec
Get() ~> route ~> check {
assert(contentType == `application/json`)
assert(responseAs[
String] == s"""{"result":["${dummyOracleEvent.announcementTLV.hex}"],"error":null}""")
assert(
responseAs[String] == s"""{"result":["${dummyOracleEvent.eventName}"],"error":null}""")
}
}

View file

@ -36,7 +36,7 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit
case ServerCommand("listevents", _) =>
complete {
oracle.listEvents().map { events =>
val strs = events.map(_.announcementTLV.hex)
val strs = events.map(_.eventName)
val json = Arr.from(strs)
Server.httpSuccess(json)
@ -127,13 +127,6 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit
case enum: EnumEventDescriptorV0TLV =>
enum.outcomes.map(outcome => Str(outcome.normStr))
case decomp: DigitDecompositionEventDescriptorV0TLV =>
val sign = decomp match {
case _: UnsignedDigitDecompositionEventDescriptor =>
Vector.empty
case _: SignedDigitDecompositionEventDescriptor =>
Vector(Str("+"), Str("-"))
}
val digits = 0.until(decomp.numDigits.toInt).map { _ =>
0
.until(decomp.base.toInt)
@ -141,7 +134,12 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit
.toVector
}
val vecs = digits :+ sign
val vecs = decomp match {
case _: UnsignedDigitDecompositionEventDescriptor =>
digits
case _: SignedDigitDecompositionEventDescriptor =>
Vector(Str("+"), Str("-")) +: digits
}
vecs.map(vec => Arr.from(vec))
}
@ -152,6 +150,15 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit
ujson.Null
}
val signedOutcomeJs = event match {
case _: PendingOracleEvent =>
ujson.Null
case emum: CompletedEnumV0OracleEvent =>
Str(emum.outcome.outcomeString)
case decomp: CompletedDigitDecompositionV0OracleEvent =>
Num(decomp.outcomeBase10.toDouble)
}
val json = Obj(
"nonces" -> event.nonces.map(n => Str(n.hex)),
"eventName" -> Str(event.eventName),
@ -165,7 +172,8 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit
"eventTLV" -> Str(event.eventTLV.hex),
"announcementTLV" -> Str(event.announcementTLV.hex),
"attestations" -> attestationJson,
"outcomes" -> outcomesJson
"outcomes" -> outcomesJson,
"signedOutcome" -> signedOutcomeJs
)
Server.httpSuccess(json)
case None =>

View file

@ -13,14 +13,16 @@ case class EnumAttestation(outcomeString: String) extends DLCAttestationType {
def bytes: ByteVector = CryptoUtil.serializeForHash(outcomeString)
}
sealed trait DigitDecompositionAttestationType extends DLCAttestationType
case class DigitDecompositionSignAttestation(positive: Boolean)
extends DLCAttestationType {
extends DigitDecompositionAttestationType {
override def outcomeString: String = if (positive) "+" else "-"
def bytes: ByteVector = CryptoUtil.serializeForHash(outcomeString)
}
case class DigitDecompositionAttestation(outcome: Int)
extends DLCAttestationType {
extends DigitDecompositionAttestationType {
override def outcomeString: String = outcome.toString
def bytes: ByteVector = CryptoUtil.serializeForHash(outcomeString)
}

View file

@ -4,6 +4,7 @@ import org.bitcoins.core.api.dlcoracle.db.EventDb
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.protocol.dlc.SigningVersion
import org.bitcoins.core.protocol.tlv._
import org.bitcoins.core.util.NumberUtil
import org.bitcoins.crypto._
import java.time.Instant
@ -70,6 +71,8 @@ sealed trait CompletedOracleEvent extends OracleEvent {
outcomes.map(_.outcomeString))
def outcomes: Vector[DLCAttestationType]
def dlcOutcome: DLCOutcomeType
}
sealed trait EnumV0OracleEvent extends OracleEvent {
@ -102,9 +105,16 @@ case class CompletedEnumV0OracleEvent(
attestation: FieldElement)
extends CompletedOracleEvent
with EnumV0OracleEvent {
require(OracleEvent.verifyAttestations(announcementTLV,
oracleAttestmentV0TLV,
signingVersion),
"Signatures given are invalid")
override def attestations: Vector[FieldElement] = Vector(attestation)
override def outcomes: Vector[DLCAttestationType] = Vector(outcome)
override def dlcOutcome: DLCOutcomeType = EnumOutcome(outcome.outcomeString)
}
sealed trait DigitDecompositionV0OracleEvent extends OracleEvent {
@ -130,10 +140,42 @@ case class CompletedDigitDecompositionV0OracleEvent(
maturationTime: Instant,
announcementSignature: SchnorrDigitalSignature,
eventDescriptorTLV: DigitDecompositionEventDescriptorV0TLV,
outcomes: Vector[DLCAttestationType],
dlcOutcome: NumericDLCOutcomeType,
attestations: Vector[FieldElement])
extends CompletedOracleEvent
with DigitDecompositionV0OracleEvent
with DigitDecompositionV0OracleEvent {
require(OracleEvent.verifyAttestations(announcementTLV,
oracleAttestmentV0TLV,
signingVersion),
"Signatures given are invalid")
val outcomeBase10: Long = {
val (digits, positive) = dlcOutcome match {
case UnsignedNumericOutcome(digits) =>
(digits, true)
case SignedNumericOutcome(positive, digits) =>
(digits, positive)
}
val base = eventDescriptorTLV.base.toInt
val numDigits = eventDescriptorTLV.numDigits.toInt
val num = NumberUtil.fromDigits(digits, base, numDigits)
if (positive) num
else num * -1
}
override def outcomes: Vector[DigitDecompositionAttestationType] =
dlcOutcome match {
case UnsignedNumericOutcome(digits) =>
digits.map(DigitDecompositionAttestation)
case SignedNumericOutcome(positive, digits) =>
val sign = DigitDecompositionSignAttestation(positive)
sign +: digits.map(DigitDecompositionAttestation)
}
}
object OracleEvent {
@ -172,18 +214,18 @@ object OracleEvent {
val attestations = sortedEventDbs.flatMap(_.attestationOpt)
val outcomes = decomp match {
val dlcOutcome = decomp match {
case _: SignedDigitDecompositionEventDescriptor =>
val sign = DigitDecompositionSignAttestation(
sortedEventDbs.head.outcomeOpt.get == "+")
val positive = sortedEventDbs.head.outcomeOpt.get == "+"
val digits = sortedEventDbs.tail.map { eventDb =>
DigitDecompositionAttestation(eventDb.outcomeOpt.get.toInt)
eventDb.outcomeOpt.get.toInt
}
sign +: digits
SignedNumericOutcome(positive, digits)
case _: UnsignedDigitDecompositionEventDescriptor =>
sortedEventDbs.map { eventDb =>
DigitDecompositionAttestation(eventDb.outcomeOpt.get.toInt)
val digits = sortedEventDbs.map { eventDb =>
eventDb.outcomeOpt.get.toInt
}
UnsignedNumericOutcome(digits)
}
CompletedDigitDecompositionV0OracleEvent(
@ -194,7 +236,7 @@ object OracleEvent {
eventDb.maturationTime,
eventDb.announcementSignature,
decomp,
outcomes,
dlcOutcome,
attestations
)
case (decomp: DigitDecompositionEventDescriptorV0TLV, None) =>

View file

@ -4,6 +4,7 @@ import org.bitcoins.core.currency.Satoshis
import org.bitcoins.core.protocol.tlv.{
DLCOutcomeType,
EnumOutcome,
SignedNumericOutcome,
UnsignedNumericOutcome
}
import org.bitcoins.core.util.{Indexed, NumberUtil}
@ -281,7 +282,7 @@ object CETCalculator {
digits: Digits,
outcomes: Vector[DLCOutcomeType]): Option[UnsignedNumericOutcome] = {
searchForPrefix(digits, outcomes) {
case outcome: EnumOutcome =>
case outcome @ (_: EnumOutcome | _: SignedNumericOutcome) =>
throw new IllegalArgumentException(
s"Expected Numeric Outcome, got $outcome")
case UnsignedNumericOutcome(digits) => digits

View file

@ -132,7 +132,7 @@ case class EnumSingleOracleInfo(announcement: OracleAnnouncementTLV)
sig)
}
}
case UnsignedNumericOutcome(_) =>
case UnsignedNumericOutcome(_) | _: SignedNumericOutcome =>
throw new IllegalArgumentException(
s"Expected EnumOutcome, got $outcome")
}
@ -177,7 +177,7 @@ case class NumericSingleOracleInfo(announcement: OracleAnnouncementTLV)
s"Too many signatures (expected at most ${nonces.length}), got $sigs")
outcome match {
case EnumOutcome(_) =>
case EnumOutcome(_) | _: SignedNumericOutcome =>
throw new IllegalArgumentException(
s"Expected numeric outcome, got $outcome")
case UnsignedNumericOutcome(digits) =>

View file

@ -17,6 +17,8 @@ case class EnumOutcome(outcome: String) extends DLCOutcomeType {
Vector(CryptoUtil.serializeForHash(outcome))
}
sealed trait NumericDLCOutcomeType extends DLCOutcomeType
/** An outcome from a multi-nonce unsigned numeric event type.
*
* If digits.length is less than the the total number of digits to be
@ -25,8 +27,27 @@ case class EnumOutcome(outcome: String) extends DLCOutcomeType {
*
* I.e. the Vector[Int] is always the most significant digits.
*/
case class UnsignedNumericOutcome(digits: Vector[Int]) extends DLCOutcomeType {
case class UnsignedNumericOutcome(digits: Vector[Int])
extends NumericDLCOutcomeType {
override lazy val serialized: Vector[ByteVector] =
digits.map(digit => CryptoUtil.serializeForHash(digit.toString))
}
/** An outcome from a multi-nonce signed numeric event type.
*
* If digits.length is less than the the total number of digits to be
* signed by the oracle then this outcome represents all outcomes prefixed
* by the given digits.
*
* I.e. the Vector[Int] is always the most significant digits.
*/
case class SignedNumericOutcome(positive: Boolean, digits: Vector[Int])
extends NumericDLCOutcomeType {
private val signOutcomeStr = if (positive) "+" else "-"
override lazy val serialized: Vector[ByteVector] =
CryptoUtil.serializeForHash(signOutcomeStr) +:
digits.map(digit => CryptoUtil.serializeForHash(digit.toString))
}

View file

@ -278,6 +278,8 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) {
s"$enumStr$outcome"
case UnsignedNumericOutcome(digits) =>
s"$unsignedNumStr" + digits.mkString("|")
case _: SignedNumericOutcome =>
throw new RuntimeException("Unknown outcome type")
},
str => {
if (str.startsWith(enumStr)) {
@ -307,6 +309,8 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) {
s"$enumStr$outcome"
case UnsignedNumericOutcome(digits) =>
s"$unsignedNumStr" + digits.mkString("|")
case _: SignedNumericOutcome =>
throw new RuntimeException("Unknown outcome type")
}
}.mkString,
str => {

View file

@ -106,6 +106,7 @@ If you use the `getevent` rpc along the oracle announcement, you can see the eve
"Republican_win",
"Democrat_win",
"other"
]
],
"signedOutcome": "Democrat_win"
}
```

View file

@ -257,9 +257,7 @@ If you use the `getevent` rpc along the oracle announcement, you can see the eve
"0",
"1"
],
[
]
"signedOutcome": 42069
]
}
```

View file

@ -14,7 +14,7 @@ checkout [this page](build-oracle-server.md).
- `getpublickey` - Get oracle's public key
- `getstakingaddress` - Get oracle's staking address
- `listevents` - Lists all oracle announcement TLVs
- `listevents` - Lists all event names
- `createenumevent` `label` `maturationtime` `outcomes` - Registers an oracle enum event
- `label` - Label for this event
- `maturationtime` - The earliest expected time an outcome will be signed, given in ISO 8601 format
@ -70,7 +70,8 @@ $ bitcoin-s-cli getevent test
"outcome1",
"outcome2",
"outcome3"
]
],
"signedOutcome": null
}
@ -87,7 +88,7 @@ $ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "createenum
{"result":"fdd824b0ba0f08e9becbf77019e246ca8a80c027585634dc1aed4b7f67442ada394b40dcb242d8a8c84893a752b93f30ff07525b0604382255ec7392fcc6f230140feb905f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd8224c000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f657131d1fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d65330474657374","error":null}
$ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getevent", "params": ["testEvent"]}' -H "Content-Type: application/json" http://127.0.0.1:9998/
{"result":{"nonces":["80e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f"],"eventName":"test","signingVersion":"DLCOracleV0SigningVersion","maturationTime":"2030-01-03T00:30:00.000Z","announcementSignature":"ba0f08e9becbf77019e246ca8a80c027585634dc1aed4b7f67442ada394b40dcb242d8a8c84893a752b93f30ff07525b0604382255ec7392fcc6f230140feb90","eventDescriptorTLV":"fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d6533","eventTLV":"fdd8224c000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f657131d1fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d65330474657374","announcementTLV":"fdd824b0ba0f08e9becbf77019e246ca8a80c027585634dc1aed4b7f67442ada394b40dcb242d8a8c84893a752b93f30ff07525b0604382255ec7392fcc6f230140feb905f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd8224c000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f657131d1fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d65330474657374","attestations":["33fd84ba8eea0a75f1568149f42e8466e1bc3422ea449532d4eeffad8586d14e"],"signatures":["80e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f33fd84ba8eea0a75f1568149f42e8466e1bc3422ea449532d4eeffad8586d14e"],"outcomes":["outcome1","outcome2","outcome3"]},"error":null}
{"result":{"nonces":["80e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f"],"eventName":"test","signingVersion":"DLCOracleV0SigningVersion","maturationTime":"2030-01-03T00:30:00.000Z","announcementSignature":"ba0f08e9becbf77019e246ca8a80c027585634dc1aed4b7f67442ada394b40dcb242d8a8c84893a752b93f30ff07525b0604382255ec7392fcc6f230140feb90","eventDescriptorTLV":"fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d6533","eventTLV":"fdd8224c000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f657131d1fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d65330474657374","announcementTLV":"fdd824b0ba0f08e9becbf77019e246ca8a80c027585634dc1aed4b7f67442ada394b40dcb242d8a8c84893a752b93f30ff07525b0604382255ec7392fcc6f230140feb905f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd8224c000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f657131d1fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d65330474657374","attestations":["33fd84ba8eea0a75f1568149f42e8466e1bc3422ea449532d4eeffad8586d14e"],"signatures":["80e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f33fd84ba8eea0a75f1568149f42e8466e1bc3422ea449532d4eeffad8586d14e"],"outcomes":["outcome1","outcome2","outcome3",],"signedOutcome": null},"error":null}
$ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "signevent", "params": ["testEvent", "outcome1"]}' -H "Content-Type: application/json" http://127.0.0.1:9998/
{"result":"fdd8687004746573745f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f33fd84ba8eea0a75f1568149f42e8466e1bc3422ea449532d4eeffad8586d14e086f7574636f6d6531","error":null}
@ -162,7 +163,8 @@ $ bitcoins-cli getevent exampleNumeric
"+",
"-"
]
]
],
"signedOutcome": null
}
@ -177,7 +179,7 @@ $ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "createnume
{"result":"fdd824fd0110647c85d333aa6fc0d7808201da9d1010b815710dc25c3d73e9cc7a7f372a7342c99144ba74d70be72920f4515daa6565bce12aedfc5a828ee37b5453454c1b575f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd822ac0004d72282a2e9532924dc8cd79685a501202332ad0d118166328cb76138414fccf37051e50fd1ab30df4717da8905e400a32c5f4d793a4ac5433ed416165dd286c47446ab1d71a550a0d604c3e86c40a3c9b12de8f08a86639068707822cd4756217139d7cabd19d6b0b9e827cdf84a4fc18c88d1882e4e096d8dfeff58759504d2657131d1fdd80a0f000a0105756e697473000000000003126578616d706c6544696769744465636f6d70","error":null}
$ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getevent", "params": ["numericExample"]}' -H "Content-Type: application/json" http://127.0.0.1:9998/
{"result":{"nonces":["7051e50fd1ab30df4717da8905e400a32c5f4d793a4ac5433ed416165dd286c4","7139d7cabd19d6b0b9e827cdf84a4fc18c88d1882e4e096d8dfeff58759504d2","7446ab1d71a550a0d604c3e86c40a3c9b12de8f08a86639068707822cd475621","d72282a2e9532924dc8cd79685a501202332ad0d118166328cb76138414fccf3"],"eventName":"numericExample","signingVersion":"DLCOracleV0SigningVersion","maturationTime":"2030-01-03T00:30:00.000Z","announcementSignature":"647c85d333aa6fc0d7808201da9d1010b815710dc25c3d73e9cc7a7f372a7342c99144ba74d70be72920f4515daa6565bce12aedfc5a828ee37b5453454c1b57","eventDescriptorTLV":"fdd80a0f000a0105756e697473000000000003","eventTLV":"fdd822ac00047051e50fd1ab30df4717da8905e400a32c5f4d793a4ac5433ed416165dd286c47139d7cabd19d6b0b9e827cdf84a4fc18c88d1882e4e096d8dfeff58759504d27446ab1d71a550a0d604c3e86c40a3c9b12de8f08a86639068707822cd475621d72282a2e9532924dc8cd79685a501202332ad0d118166328cb76138414fccf3657131d1fdd80a0f000a0105756e697473000000000003126578616d706c6544696769744465636f6d70","announcementTLV":"fdd824fd0110647c85d333aa6fc0d7808201da9d1010b815710dc25c3d73e9cc7a7f372a7342c99144ba74d70be72920f4515daa6565bce12aedfc5a828ee37b5453454c1b575f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd822ac00047051e50fd1ab30df4717da8905e400a32c5f4d793a4ac5433ed416165dd286c47139d7cabd19d6b0b9e827cdf84a4fc18c88d1882e4e096d8dfeff58759504d27446ab1d71a550a0d604c3e86c40a3c9b12de8f08a86639068707822cd475621d72282a2e9532924dc8cd79685a501202332ad0d118166328cb76138414fccf3657131d1fdd80a0f000a0105756e697473000000000003126578616d706c6544696769744465636f6d70","attestations":null,"signatures":null,"outcomes":[["0","1","2","3","4","5","6","7","8","9"],["0","1","2","3","4","5","6","7","8","9"],["0","1","2","3","4","5","6","7","8","9"],["+","-"]]},"error":null}
{"result":{"nonces":["7051e50fd1ab30df4717da8905e400a32c5f4d793a4ac5433ed416165dd286c4","7139d7cabd19d6b0b9e827cdf84a4fc18c88d1882e4e096d8dfeff58759504d2","7446ab1d71a550a0d604c3e86c40a3c9b12de8f08a86639068707822cd475621","d72282a2e9532924dc8cd79685a501202332ad0d118166328cb76138414fccf3"],"eventName":"numericExample","signingVersion":"DLCOracleV0SigningVersion","maturationTime":"2030-01-03T00:30:00.000Z","announcementSignature":"647c85d333aa6fc0d7808201da9d1010b815710dc25c3d73e9cc7a7f372a7342c99144ba74d70be72920f4515daa6565bce12aedfc5a828ee37b5453454c1b57","eventDescriptorTLV":"fdd80a0f000a0105756e697473000000000003","eventTLV":"fdd822ac00047051e50fd1ab30df4717da8905e400a32c5f4d793a4ac5433ed416165dd286c47139d7cabd19d6b0b9e827cdf84a4fc18c88d1882e4e096d8dfeff58759504d27446ab1d71a550a0d604c3e86c40a3c9b12de8f08a86639068707822cd475621d72282a2e9532924dc8cd79685a501202332ad0d118166328cb76138414fccf3657131d1fdd80a0f000a0105756e697473000000000003126578616d706c6544696769744465636f6d70","announcementTLV":"fdd824fd0110647c85d333aa6fc0d7808201da9d1010b815710dc25c3d73e9cc7a7f372a7342c99144ba74d70be72920f4515daa6565bce12aedfc5a828ee37b5453454c1b575f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd822ac00047051e50fd1ab30df4717da8905e400a32c5f4d793a4ac5433ed416165dd286c47139d7cabd19d6b0b9e827cdf84a4fc18c88d1882e4e096d8dfeff58759504d27446ab1d71a550a0d604c3e86c40a3c9b12de8f08a86639068707822cd475621d72282a2e9532924dc8cd79685a501202332ad0d118166328cb76138414fccf3657131d1fdd80a0f000a0105756e697473000000000003126578616d706c6544696769744465636f6d70","attestations":null,"signatures":null,"outcomes":[["0","1","2","3","4","5","6","7","8","9"],["0","1","2","3","4","5","6","7","8","9"],["0","1","2","3","4","5","6","7","8","9"],["+","-"]],"signedOutcome": null},"error":null}
$ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "signdigits", "params": ["numericExample", 123]}' -H "Content-Type: application/json" http://127.0.0.1:9998/
{"result":"fdd868fd013d126578616d706c6544696769744465636f6d705f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e521150004d72282a2e9532924dc8cd79685a501202332ad0d118166328cb76138414fccf3d0646c9efd9523274014841ba24bf63219d5650d1682209d7e48af009d58e6d87051e50fd1ab30df4717da8905e400a32c5f4d793a4ac5433ed416165dd286c4c025dfd1e39de77e0418fa7d39abf2e9daf55d7fe34f8e312368cb4d45b4d4b97446ab1d71a550a0d604c3e86c40a3c9b12de8f08a86639068707822cd475621700347c52af088eda9a0245385094518134e73bb997102e11f6de0aeb36af7237139d7cabd19d6b0b9e827cdf84a4fc18c88d1882e4e096d8dfeff58759504d2f9e7a9e183b0836ad58dd646d9ab123132397109e4f51c5842958932a81bacd1012b013101320133","error":null}