handleRequestProof method

Future<void> handleRequestProof(
  1. RequestAncestorProofCommand cmd
)

Ask RequestAncestorProofCommand.txid's counterparty for a fresh proof.

App-triggered, one request per call: nothing here retries or polls, so a peer is never pestered by the library.

Implementation

Future<void> handleRequestProof(RequestAncestorProofCommand cmd) async {
  final requestId = cmd.requestId;
  try {
    final tx = await _storage.getTransaction(cmd.txid, walletId: cmd.walletId);
    if (tx == null) {
      _emitEvent(AncestorProofRequestedEvent(
        walletId: cmd.walletId,
        txid: cmd.txid,
        requestId: requestId,
        success: false,
        error: 'no transaction ${cmd.txid} is stored for wallet ${cmd.walletId}',
      ));
      return;
    }

    // Who handed us this payment. Null on rows written before markers
    // existed, and on payments an app recorded without one: then there is
    // nobody to ask, and only the block returning can restore the output.
    final marker = tx.counterpartyMarker;
    if (marker == null || marker.isEmpty) {
      _emitEvent(AncestorProofRequestedEvent(
        walletId: cmd.walletId,
        txid: cmd.txid,
        requestId: requestId,
        success: false,
        error: 'no counterparty marker is recorded for ${cmd.txid}, so there is nobody to ask for a '
            'fresh proof: this output is unrecoverable by request and can only be restored by its '
            "ancestor's block returning to the active chain",
      ));
      return;
    }

    final ancestors = cmd.ancestorTxids.isNotEmpty
        ? cmd.ancestorTxids
        : await _awaitedAncestorsOf(cmd.walletId, cmd.txid);

    _pending[requestId] = _PendingProofRequest(
      walletId: cmd.walletId,
      txid: cmd.txid,
      peerId: marker,
    );

    _emitEvent(P2PMessageToSendEvent(
      toPeerId: marker,
      messageType: proofRequestType,
      payload: {
        'requestId': requestId,
        'txid': cmd.txid,
        'ancestors': ancestors,
      },
    ));
    _emitEvent(AncestorProofRequestedEvent(
      walletId: cmd.walletId,
      txid: cmd.txid,
      requestId: requestId,
      toPeerId: marker,
      ancestorTxids: ancestors,
      success: true,
    ));
  } catch (e, st) {
    _log.warning('Proof request for ${cmd.txid} failed: $e', e, st);
    _pending.remove(requestId);
    _emitEvent(AncestorProofRequestedEvent(
      walletId: cmd.walletId,
      txid: cmd.txid,
      requestId: requestId,
      success: false,
      error: e.toString(),
    ));
  }
}