@@ -1075,9 +1075,14 @@ func (p *ChainPorter) stateStep(currentPkg sendPackage) (*sendPackage, error) {
10751075 // At this point, we have everything we need to sign our _virtual_
10761076 // transaction on the Taproot Asset layer.
10771077 case SendStateVirtualSign :
1078+ ctx , cancel := p .WithCtxQuitNoTimeout ()
1079+ defer cancel ()
1080+
10781081 vPackets := currentPkg .VirtualPackets
10791082 err := tapsend .ValidateVPacketVersions (vPackets )
10801083 if err != nil {
1084+ p .unlockInputs (ctx , & currentPkg )
1085+
10811086 return nil , err
10821087 }
10831088
@@ -1091,6 +1096,8 @@ func (p *ChainPorter) stateStep(currentPkg sendPackage) (*sendPackage, error) {
10911096
10921097 _ , err := p .cfg .AssetWallet .SignVirtualPacket (vPkt )
10931098 if err != nil {
1099+ p .unlockInputs (ctx , & currentPkg )
1100+
10941101 return nil , fmt .Errorf ("unable to sign and " +
10951102 "commit virtual packet: %w" , err )
10961103 }
@@ -1125,6 +1132,8 @@ func (p *ChainPorter) stateStep(currentPkg sendPackage) (*sendPackage, error) {
11251132 ctx , tapsend .SendConfTarget ,
11261133 )
11271134 if err != nil {
1135+ p .unlockInputs (ctx , & currentPkg )
1136+
11281137 return nil , fmt .Errorf ("unable to estimate " +
11291138 "fee: %w" , err )
11301139 }
@@ -1148,6 +1157,8 @@ func (p *ChainPorter) stateStep(currentPkg sendPackage) (*sendPackage, error) {
11481157 currentPkg .InputCommitments ,
11491158 )
11501159 if err != nil {
1160+ p .unlockInputs (ctx , & currentPkg )
1161+
11511162 return nil , fmt .Errorf ("unable to create passive " +
11521163 "assets: %w" , err )
11531164 }
@@ -1156,6 +1167,8 @@ func (p *ChainPorter) stateStep(currentPkg sendPackage) (*sendPackage, error) {
11561167 len (currentPkg .PassiveAssets ))
11571168 err = wallet .SignPassiveAssets (currentPkg .PassiveAssets )
11581169 if err != nil {
1170+ p .unlockInputs (ctx , & currentPkg )
1171+
11591172 return nil , fmt .Errorf ("unable to sign passive " +
11601173 "assets: %w" , err )
11611174 }
@@ -1168,6 +1181,8 @@ func (p *ChainPorter) stateStep(currentPkg sendPackage) (*sendPackage, error) {
11681181 },
11691182 )
11701183 if err != nil {
1184+ p .unlockInputs (ctx , & currentPkg )
1185+
11711186 return nil , fmt .Errorf ("unable to anchor virtual " +
11721187 "transactions: %w" , err )
11731188 }
@@ -1382,10 +1397,44 @@ func (p *ChainPorter) stateStep(currentPkg sendPackage) (*sendPackage, error) {
13821397
13831398// unlockInputs unlocks the inputs that were locked for the given package.
13841399func (p * ChainPorter ) unlockInputs (ctx context.Context , pkg * sendPackage ) {
1385- if pkg == nil || pkg .AnchorTx == nil || pkg .AnchorTx .FundedPsbt == nil {
1400+ // Impossible state, but catch it anyway.
1401+ if pkg == nil {
1402+ return
1403+ }
1404+
1405+ // If we haven't even attempted to broadcast yet, we're still in a state
1406+ // where we give feedback to the user synchronously, as we haven't
1407+ // created an on-chain transaction that we need to await confirmation.
1408+ // We also haven't written the transfer to disk yet, so we can just
1409+ // release/unlock the _asset_ level UTXOs so the user can try again. We
1410+ // sanity-check that we have known input commitments to unlock, since
1411+ // that might not always be the case (for example if another party
1412+ // contributes inputs).
1413+ if pkg .SendState < SendStateStorePreBroadcast &&
1414+ len (pkg .InputCommitments ) > 0 {
1415+
1416+ for prevID := range pkg .InputCommitments {
1417+ log .Debugf ("Unlocking input %v" , prevID .OutPoint )
1418+
1419+ err := p .cfg .AssetWallet .ReleaseCoins (
1420+ ctx , prevID .OutPoint ,
1421+ )
1422+ if err != nil {
1423+ log .Warnf ("Unable to unlock input %v: %v" ,
1424+ prevID .OutPoint , err )
1425+ }
1426+ }
1427+ }
1428+
1429+ // If we're in another state, the anchor transaction has been created,
1430+ // and we can't simply unlock the asset level inputs. This will likely
1431+ // require manual intervention.
1432+ if pkg .AnchorTx == nil || pkg .AnchorTx .FundedPsbt == nil {
13861433 return
13871434 }
13881435
1436+ // We need to unlock any _BTC_ level inputs we locked for the anchor
1437+ // transaction.
13891438 for _ , op := range pkg .AnchorTx .FundedPsbt .LockedUTXOs {
13901439 err := p .cfg .Wallet .UnlockInput (ctx , op )
13911440 if err != nil {
0 commit comments