onCommandFailure method

  1. @override
Future<void> onCommandFailure(
  1. Command command,
  2. dynamic error
)

Send error responses when command processing fails Only active when aggregate is used as an actor in the actor system

Implementation

@override
Future<void> onCommandFailure(Command command, dynamic error) async {
  await super.onCommandFailure(command, error);

  // The events behind a prepared success reply were not journaled.
  _repliesAwaitingPersist.remove(command.commandId);

  // Key material was written before the WalletCreatedEvent; if the event
  // could not be persisted, take the secrets back out (best effort).
  final pendingWalletId = _keyMaterialAwaitingPersist.remove(command.commandId);
  if (pendingWalletId != null) {
    _log.warning('Wallet $pendingWalletId: creation failed after key material '
        'was stored; removing it again: $error');
    await _keys.removeKeyMaterial(pendingWalletId, cause: error ?? 'unknown');
  }

  // Only send responses if we're running in an actor system
  if (!_isInActorSystem()) {
    return;
  }

  // Use captured sender keyed by command ID (same reasoning as onCommandProcessed)
  final sender = _capturedSenders[command.commandId];
  if (sender == null) {
    return;
  }
  if (!_failureReplied.add(command.commandId)) {
    return;
  }

  final errorMessage = error.toString();

  if (command is CreateWalletCommand) {
    sender.tell(WalletCreatedResponse(
      walletId: command.walletId,
      rootAddress: '',
      success: false,
      error: errorMessage,
    ));
  } else if (command is GenerateAddressCommand) {
    sender.tell(AddressGeneratedResponse(
      walletId: command.walletId,
      address: '',
      derivationIndex: 0,
      success: false,
      error: errorMessage,
      metadata: command.metadata, // Pass through metadata even on error
    ));
  } else if (command is ReserveUTXOCommand) {
    sender.tell(UTXOReservedResponse(
      walletId: command.walletId,
      utxoKey: command.utxoKey,
      reservedByTxId: command.reservedByTxId,
      success: false,
      error: errorMessage,
    ));
  } else if (command is ReserveUTXOsCommand) {
    sender.tell(UTXOReservedResponse(
      walletId: command.walletId,
      utxoKey: command.utxoKeys.join(','),
      reservedByTxId: command.reservationId,
      success: false,
      error: errorMessage,
    ));
  } else if (command is BuildFundingTransactionCommand) {
    sender.tell(FundingTransactionBuiltResponse(
      walletId: command.walletId,
      correlationId: command.correlationId,
      channelId: command.channelId,
      fundingTxHex: '',
      fundingTxId: '',
      fundingOutputIndex: 0,
      success: false,
      error: errorMessage,
    ));
  } else if (command is SignTransactionCommand) {
    sender.tell(TransactionSignedResponse(
      walletId: command.walletId,
      txid: command.transactionId,
      signedHex: '',
      success: false,
      error: errorMessage,
    ));
  } else if (command is SignMultisigTransactionCommand) {
    sender.tell(MultisigTransactionSignedResponse(
      walletId: command.walletId,
      txid: '',
      originalTransactionId: command.transactionId,
      signedHex: '',
      signatureHex: '',
      success: false,
      error: errorMessage,
    ));
  } else if (command is SignInputCommand) {
    sender.tell(InputSignedResponse(
      walletId: command.walletId,
      commandId: command.commandId,
      inputIndex: command.inputIndex,
      signatureHex: '',
      publicKeyHex: '',
      success: false,
      error: errorMessage,
    ));
  } else if (command is CancelDeferredSpendCommand) {
    sender.tell(DeferredSpendCancelledResponse(
      walletId: command.walletId,
      txid: command.txid,
      success: false,
      error: errorMessage,
    ));
  } else if (command is ReclaimDeferredSpendCommand) {
    sender.tell(DeferredSpendReclaimedResponse(
      walletId: command.walletId,
      txid: command.txid,
      reclaimTxid: command.reclaimTxid,
      success: false,
      error: errorMessage,
    ));
  } else if (command is AddWatchAddressCommand) {
    sender.tell(WatchAddressAddedResponse(
      walletId: command.walletId,
      address: command.address,
      success: false,
      error: errorMessage,
    ));
  } else {
    // Every other command: the aggregate has no reply of its own for it,
    // so the failure is reported in the shape every caller understands
    // (bead libspiffy-kl4i).
    sender.tell(WalletCommandFailed(
      walletId: command is WalletCommand ? command.walletId : aggregateId,
      request: command.runtimeType.toString(),
      error: errorMessage,
    ));
  }
}