syntax = "proto3";

package chainrpc;

option go_package = "github.com/lightningnetwork/lnd/lnrpc/chainrpc";

// ChainNotifier is a service that can be used to get information about the
// chain backend by registering notifiers for chain events.
service ChainNotifier {
    /*
    RegisterConfirmationsNtfn is a synchronous response-streaming RPC that
    registers an intent for a client to be notified once a confirmation request
    has reached its required number of confirmations on-chain.

    A confirmation request must have a valid output script. It is also possible
    to give a transaction ID. If the transaction ID is not set, a notification
    is sent once the output script confirms. If the transaction ID is also set,
    a notification is sent once the output script confirms in the given
    transaction.
    */
    rpc RegisterConfirmationsNtfn (ConfRequest) returns (stream ConfEvent);

    /*
    RegisterSpendNtfn is a synchronous response-streaming RPC that registers an
    intent for a client to be notification once a spend request has been spent
    by a transaction that has confirmed on-chain.

    A client can specify whether the spend request should be for a particular
    outpoint  or for an output script by specifying a zero outpoint.
    */
    rpc RegisterSpendNtfn (SpendRequest) returns (stream SpendEvent);

    /*
    RegisterBlockEpochNtfn is a synchronous response-streaming RPC that
    registers an intent for a client to be notified of blocks in the chain. The
    stream will return a hash and height tuple of a block for each new/stale
    block in the chain. It is the client's responsibility to determine whether
    the tuple returned is for a new or stale block in the chain.

    A client can also request a historical backlog of blocks from a particular
    point. This allows clients to be idempotent by ensuring that they do not
    missing processing a single block within the chain.
    */
    rpc RegisterBlockEpochNtfn (BlockEpoch) returns (stream BlockEpoch);
}

message ConfRequest {
    /*
    The transaction hash for which we should request a confirmation notification
    for. If set to a hash of all zeros, then the confirmation notification will
    be requested for the script instead.
    */
    bytes txid = 1;

    /*
    An output script within a transaction with the hash above which will be used
    by light clients to match block filters. If the transaction hash is set to a
    hash of all zeros, then a confirmation notification will be requested for
    this script instead.
    */
    bytes script = 2;

    /*
    The number of desired confirmations the transaction/output script should
    reach before dispatching a confirmation notification.
    */
    uint32 num_confs = 3;

    /*
    The earliest height in the chain for which the transaction/output script
    could have been included in a block. This should in most cases be set to the
    broadcast height of the transaction/output script.
    */
    uint32 height_hint = 4;

    /*
    If true, then the block that mines the specified txid/script will be
    included in eventual the notification event.
    */
    bool include_block = 5;
}

message ConfDetails {
    // The raw bytes of the confirmed transaction.
    bytes raw_tx = 1;

    // The hash of the block in which the confirmed transaction was included in.
    bytes block_hash = 2;

    // The height of the block in which the confirmed transaction was included
    // in.
    uint32 block_height = 3;

    // The index of the confirmed transaction within the block.
    uint32 tx_index = 4;

    /*
    The raw bytes of the block that mined the transaction. Only included if
    include_block was set in the request.
    */
    bytes raw_block = 5;
}

message Reorg {
    // TODO(wilmer): need to know how the client will use this first.
}

message ConfEvent {
    oneof event {
        /*
        An event that includes the confirmation details of the request
        (txid/ouput script).
        */
        ConfDetails conf = 1;

        /*
        An event send when the transaction of the request is reorged out of the
        chain.
        */
        Reorg reorg = 2;
    }
}

message Outpoint {
    // The hash of the transaction.
    bytes hash = 1;

    // The index of the output within the transaction.
    uint32 index = 2;
}

message SpendRequest {
    /*
    The outpoint for which we should request a spend notification for. If set to
    a zero outpoint, then the spend notification will be requested for the
    script instead. A zero or nil outpoint is not supported for Taproot spends
    because the output script cannot reliably be computed from the witness alone
    and the spent output script is not always available in the rescan context.
    So an outpoint must _always_ be specified when registering a spend
    notification for a Taproot output.
    */
    Outpoint outpoint = 1;

    /*
    The output script for the outpoint above. This will be used by light clients
    to match block filters. If the outpoint is set to a zero outpoint, then a
    spend notification will be requested for this script instead.
    */
    bytes script = 2;

    /*
    The earliest height in the chain for which the outpoint/output script could
    have been spent. This should in most cases be set to the broadcast height of
    the outpoint/output script.
    */
    uint32 height_hint = 3;

    // TODO(wilmer): extend to support num confs on spending tx.
}

message SpendDetails {
    // The outpoint was that spent.
    Outpoint spending_outpoint = 1;

    // The raw bytes of the spending transaction.
    bytes raw_spending_tx = 2;

    // The hash of the spending transaction.
    bytes spending_tx_hash = 3;

    // The input of the spending transaction that fulfilled the spend request.
    uint32 spending_input_index = 4;

    // The height at which the spending transaction was included in a block.
    uint32 spending_height = 5;
}

message SpendEvent {
    oneof event {
        /*
        An event that includes the details of the spending transaction of the
        request (outpoint/output script).
        */
        SpendDetails spend = 1;

        /*
        An event sent when the spending transaction of the request was
        reorged out of the chain.
        */
        Reorg reorg = 2;
    }
}

message BlockEpoch {
    // The hash of the block.
    bytes hash = 1;

    // The height of the block.
    uint32 height = 2;
}
