diff --git a/chain/ring.go b/chain/ring.go index a423aa1..1f4746c 100644 --- a/chain/ring.go +++ b/chain/ring.go @@ -55,9 +55,11 @@ func (c *Chain) GetRingOutputs(height, amount uint64, offsets []uint64) ([]types // TxOutHTLC selects redeem vs refund based on whether the spending height is // before or after the contract expiration. func ringOutputSpendKey(height uint64, target types.TxOutTarget) (types.PublicKey, error) { - switch t := target.(type) { - case types.TxOutToKey: + if t, ok := types.AsTxOutToKey(target); ok { return t.Key, nil + } + + switch t := target.(type) { case types.TxOutMultisig: if len(t.Keys) == 0 { return types.PublicKey{}, fmt.Errorf("unsupported multisig target with no keys") diff --git a/tui/explorer_model.go b/tui/explorer_model.go index 96c73f9..31dce3d 100644 --- a/tui/explorer_model.go +++ b/tui/explorer_model.go @@ -325,7 +325,7 @@ func (m *ExplorerModel) viewTxDetail() string { for i, output := range tx.Vout { switch v := output.(type) { case types.TxOutputBare: - if targetKey, ok := v.Target.(types.TxOutToKey); ok { + if targetKey, ok := types.AsTxOutToKey(v.Target); ok { b.WriteString(fmt.Sprintf(" [%d] bare amount=%d key=%x\n", i, v.Amount, targetKey.Key[:4])) } else { b.WriteString(fmt.Sprintf(" [%d] bare amount=%d target=%T\n", i, v.Amount, v.Target)) diff --git a/types/transaction.go b/types/transaction.go index 6652d3b..7c0ea1d 100644 --- a/types/transaction.go +++ b/types/transaction.go @@ -121,6 +121,13 @@ type TxOutTarget interface { TargetType() uint8 } +// AsTxOutToKey returns target as a TxOutToKey when it is a standard +// transparent output target. +func AsTxOutToKey(target TxOutTarget) (TxOutToKey, bool) { + v, ok := target.(TxOutToKey) + return v, ok +} + // TxOutToKey is the txout_to_key target variant. On the wire it is // serialised as a 33-byte packed blob: 32-byte public key + 1-byte mix_attr. type TxOutToKey struct { @@ -219,7 +226,7 @@ func (t TxInputHTLC) InputType() uint8 { return InputTypeHTLC } // TxInputMultisig spends from a multisig output (HF1+). type TxInputMultisig struct { Amount uint64 - MultisigOutID Hash // 32-byte hash identifying the multisig output + MultisigOutID Hash // 32-byte hash identifying the multisig output SigsCount uint64 EtcDetails []byte // opaque variant vector } diff --git a/types/transaction_test.go b/types/transaction_test.go index 270b273..166f2d3 100644 --- a/types/transaction_test.go +++ b/types/transaction_test.go @@ -14,6 +14,25 @@ func TestTxOutToKey_TargetType_Good(t *testing.T) { } } +func TestAsTxOutToKey_Good(t *testing.T) { + target, ok := AsTxOutToKey(TxOutToKey{Key: PublicKey{1}, MixAttr: 7}) + if !ok { + t.Fatal("AsTxOutToKey: expected true for TxOutToKey target") + } + if target.Key != (PublicKey{1}) { + t.Errorf("Key: got %x, want %x", target.Key, PublicKey{1}) + } + if target.MixAttr != 7 { + t.Errorf("MixAttr: got %d, want %d", target.MixAttr, 7) + } +} + +func TestAsTxOutToKey_Bad(t *testing.T) { + if _, ok := AsTxOutToKey(TxOutHTLC{}); ok { + t.Fatal("AsTxOutToKey: expected false for non-to-key target") + } +} + func TestTxOutMultisig_TargetType_Good(t *testing.T) { var target TxOutTarget = TxOutMultisig{MinimumSigs: 2, Keys: []PublicKey{{1}, {2}}} if target.TargetType() != TargetTypeMultisig { diff --git a/wallet/scanner.go b/wallet/scanner.go index f3aee4b..8cc36aa 100644 --- a/wallet/scanner.go +++ b/wallet/scanner.go @@ -64,7 +64,7 @@ func (s *V1Scanner) ScanTransaction(tx *types.Transaction, txHash types.Hash, continue } - targetKey, ok := bare.Target.(types.TxOutToKey) + targetKey, ok := types.AsTxOutToKey(bare.Target) if !ok { continue }