# All files / lib/messages OracleAttestationV0.ts

93.88% Statements 46/49
50% Branches 1/2
66.67% Functions 4/6
93.62% Lines 44/47

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    1341x
    1x

    1x

    1x
    1x

    3x
    3x

    3x
    3x

    3x
    3x
    3x

    3x

    3x

    3x
    3x
    3x

    3x
    3x
    3x
    3x

    3x

    6x

    6x

    6x

    2x

    2x
    2x

    2x

    3x
    3x

    3x
    3x
    3x
    3x
    3x

    3x
    3x

    3x
    3x
    3x

    3x
    3x

    3x

     import { BufferReader, BufferWriter } from '@node-dlc/bufio';
    import { math, verify } from 'bip-schnorr';

    import { MessageType } from '../MessageType';
    import { IDlcMessage } from './DlcMessage';

    /**
     * In order to make it possible to hold oracles accountable in cases where
     * they do not release a signature for an event outcome, there needs to be
     * a proof that an oracle has committed to a given outcome. This proof is
     * given in a so-called oracle announcement, which contains an oracle event
     * together with the oracle public key and a signature over its serialization,
     * which must be valid with respect to the specified public key.
     *
     * This also makes it possible for users to obtain oracle event information
     * from an un-trusted peer while being guaranteed that it originates from a
     * given oracle.
     */
    export class OracleAttestationV0 implements IDlcMessage {
      public static type = MessageType.OracleAttestationV0;

      /**
       * Deserializes an oracle_announcement_v0 message
       * @param buf
       */
      public static deserialize(buf: Buffer): OracleAttestationV0 {
        const instance = new OracleAttestationV0();
        const reader = new BufferReader(buf);

        reader.readBigSize(); // read type
        instance.length = reader.readBigSize();

        const eventIdLength = reader.readBigSize();
        const eventIdBuf = reader.readBytes(Number(eventIdLength));
        instance.eventId = eventIdBuf.toString();

        instance.oraclePubkey = reader.readBytes(32);

        const numSignatures = reader.readUInt16BE();

        for (let i = 0; i < numSignatures; i++) {
          const signature = reader.readBytes(64);
          instance.signatures.push(signature);
        }

        while (!reader.eof) {
          const outcomeLen = reader.readBigSize();
          const outcomeBuf = reader.readBytes(Number(outcomeLen));
          instance.outcomes.push(outcomeBuf.toString());
        }

        return instance;
      }

      /**
       * The type for oracle_announcement_v0 message. oracle_announcement_v0 = 55332
       */
      public type = OracleAttestationV0.type;

      public length: bigint;

      public eventId: string;

      public oraclePubkey: Buffer;

      public signatures: Buffer[] = [];

      public outcomes: string[] = [];

      public validate(): void {
        Iif (this.signatures.length !== this.outcomes.length) {
          throw Error('signature and outcome length must be the same');
        }

        // Verify attestation outcome signatures
        for (let i = 0; i < this.signatures.length; i++) {
          const msg = math.taggedHash(
            'DLC/oracle/attestation/v0',
            this.outcomes[i],
          );
          verify(this.oraclePubkey, msg, this.signatures[i]);
        }
      }

      /**
       * Converts oracle_attestation_v0 to JSON
       */
      public toJSON(): OracleAttestationV0JSON {
        return {
          type: this.type,
          eventId: this.eventId,
          oraclePubkey: this.oraclePubkey.toString('hex'),
          signatures: this.signatures.map((sig) => sig.toString('hex')),
          outcomes: this.outcomes,
        };
      }

      /**
       * Serializes the oracle_announcement_v0 message into a Buffer
       */
      public serialize(): Buffer {
        const writer = new BufferWriter();
        writer.writeBigSize(this.type);

        const dataWriter = new BufferWriter();
        dataWriter.writeBigSize(this.eventId.length);
        dataWriter.writeBytes(Buffer.from(this.eventId));
        dataWriter.writeBytes(this.oraclePubkey);
        dataWriter.writeUInt16BE(this.signatures.length);

        for (const signature of this.signatures) {
          dataWriter.writeBytes(signature);
        }

        for (const outcome of this.outcomes) {
          dataWriter.writeBigSize(outcome.length);
          dataWriter.writeBytes(Buffer.from(outcome));
        }

        writer.writeBigSize(dataWriter.size);
        writer.writeBytes(dataWriter.toBuffer());

        return writer.toBuffer();
      }
    }

    export interface OracleAttestationV0JSON {
      type: number;
      eventId: string;
      oraclePubkey: string;
      signatures: string[];
      outcomes: string[];
    }