示例#1
0
        public override ContractInfo ReadJson(JsonReader reader, Type objectType, [AllowNull] ContractInfo existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            if (reader.TokenType != JsonToken.StartObject)
            {
                throw new JsonObjectException("ContractInfo is expecting a json object", reader);
            }
            var cd = serializer.Deserialize <ContractData>(reader);

            if (cd?.Sats is null || (cd?.Outcome is null && cd?.SHA256 is null))
            {
                throw new JsonObjectException("Invalid contract info (missing fields)", reader);
            }

            DiscreteOutcome outcome = cd.Outcome is string?new DiscreteOutcome(cd.Outcome)
                                                                                                          : new DiscreteOutcome(Encoders.Hex.DecodeData(cd.SHA256));

            if (cd.Outcome is string && cd.SHA256 is string)
            {
                if (outcome.Hash.AsSpan().SequenceCompareTo(Encoders.Hex.DecodeData(cd.SHA256)) != 0)
                {
                    throw new JsonObjectException("Invalid contract info (invalid sha256 for the outcome)", reader);
                }
            }
            return(new ContractInfo(outcome, cd.Sats));
        }
示例#2
0
        protected override async Task InvokeAsyncBase(InvocationContext context)
        {
            var outcome = context.ParseResult.CommandResult.GetArgumentValueOrDefault <string>("outcome")?.Trim();
            var force   = context.ParseResult.ValueForOption <bool>("force");

            if (outcome is null)
            {
                throw new CommandOptionRequiredException("outcome");
            }
            EventFullName evt    = context.GetEventName();
            var           oracle = await Repository.GetOracle(evt.OracleName);

            if (oracle is null)
            {
                throw new CommandException("name", "This oracle does not exists");
            }

            var discreteOutcome = new DiscreteOutcome(outcome);
            var evtObj          = await Repository.GetEvent(evt);

            if (evtObj?.Nonce is null)
            {
                throw new CommandException("name", "This event does not exists");
            }
            if (evtObj?.NonceKeyPath is null)
            {
                throw new CommandException("name", "You did not generated this event");
            }
            outcome = evtObj.Outcomes.FirstOrDefault(o => o.Equals(outcome, StringComparison.OrdinalIgnoreCase));
            if (outcome is null)
            {
                throw new CommandException("outcome", "This outcome does not exists in this event");
            }
            var key = oracle.RootedKeyPath is RootedKeyPath ? await Repository.GetKey(oracle.RootedKeyPath) : null;

            if (key is null)
            {
                throw new CommandException("name", "You do not own the keys of this oracle");
            }
            if (evtObj.Attestations?.ContainsKey(outcome) is true)
            {
                throw new CommandException("outcome", "This outcome has already been attested");
            }
            if (evtObj.Attestations != null && evtObj.Attestations.Count > 0 && !force)
            {
                throw new CommandException("outcome", "An outcome has already been attested, attesting another one could leak the private key of your oracle. Use -f to force your action.");
            }
            var kValue = await Repository.GetKey(evtObj.NonceKeyPath);

            key.ToECPrivKey().TrySignBIP140(discreteOutcome.Hash, new PrecomputedNonceFunctionHardened(kValue.ToECPrivKey().ToBytes()), out var sig);
            var oracleAttestation = new Key(sig !.s.ToBytes());

            if (await Repository.AddAttestation(evt, oracleAttestation) != outcome)
            {
                throw new InvalidOperationException("Error while validating reveal");
            }
            context.Console.Out.Write(oracleAttestation.ToHex());
        }
        public override ContractInfo ReadJson(JsonReader reader, Type objectType, [AllowNull] ContractInfo existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            if (reader.TokenType != JsonToken.StartObject)
            {
                throw new JsonObjectException("ContractInfo is expecting a json object", reader);
            }
            var cd = serializer.Deserialize <ContractData>(reader);

            if (cd?.Sats is null || cd?.SHA256 is null)
            {
                throw new JsonObjectException("Invalid contract info (missing fields)", reader);
            }

            DiscreteOutcome outcome = new DiscreteOutcome(Encoders.Hex.DecodeData(cd.SHA256));

            return(new ContractInfo(outcome, cd.Sats));
        }
示例#4
0
 public bool TryComputeSigpoint(DiscreteOutcome outcome, out ECPubKey?sigpoint)
 {
     return(PubKey.TryComputeSigPoint(outcome.Hash, RValue, out sigpoint));
 }
示例#5
0
        public async Task <DiscreteOutcome?> AddAttestation(EventFullName name, Key oracleAttestation)
        {
            var oracles = await GetOracles();

            var oracle = GetOracle(name.OracleName, oracles);

            if (oracle?.PubKey is null)
            {
                return(null);
            }
            var events = await GetEvents(oracle);

            var evt = events.FirstOrDefault(e => e.Name.Equals(name.Name, StringComparison.OrdinalIgnoreCase));

            if (evt?.Nonce is null)
            {
                return(null);
            }
            var attestation = oracleAttestation.ToECPrivKey();
            var sig         = evt.Nonce.CreateSchnorrSignature(attestation);

            if (sig is null)
            {
                return(null);
            }
            foreach (var outcome in evt.Outcomes)
            {
                var discreteOutcome = new DiscreteOutcome(outcome);
                if (!oracle.PubKey.SigVerifyBIP340(sig, discreteOutcome.Hash))
                {
                    continue;
                }
                evt.Attestations ??= new Dictionary <string, Key>();
                if (!evt.Attestations.TryAdd(outcome, oracleAttestation))
                {
                    return(null);
                }
                // If we have two attestation for the same event, we can recover the private
                // key of the oracle
                if (evt.Attestations.Count > 1 && oracle.RootedKeyPath is null)
                {
                    var sigs = evt.Attestations.Select(kv => (Outcome: new DiscreteOutcome(kv.Key),
                                                              Signature: evt.Nonce.CreateSchnorrSignature(kv.Value.ToECPrivKey()) ?? throw new InvalidOperationException("Invalid signature in attestations")))
                               .Take(2)
                               .ToArray();
                    if (!oracle.PubKey.TryExtractPrivateKey(
                            sigs[0].Outcome.Hash, sigs[0].Signature,
                            sigs[1].Outcome.Hash, sigs[1].Signature, out var extracted) || extracted is null)
                    {
                        throw new InvalidOperationException("Could not recover the private key of the oracle, this should never happen");
                    }
                    var k = new Key(extracted.ToBytes());
                    oracle.RootedKeyPath = new RootedKeyPath(k.PubKey.GetHDFingerPrint(), new KeyPath());
                    await SaveOracles(oracles);

                    if (!KeySetExists(k.PubKey.GetHDFingerPrint()))
                    {
                        await SaveKeyset(k.PubKey.GetHDFingerPrint(), new Keyset()
                        {
                            SingleKey = k
                        });
                    }
                }
                await SaveEvents(oracle, events);

                return(discreteOutcome);
            }
            return(null);
        }
示例#6
0
 public ContractInfo(DiscreteOutcome outcome, Money payout)
 {
     Payout  = payout;
     Outcome = outcome;
 }