diff --git a/chain/ring.go b/chain/ring.go index b698f5a..ae34916 100644 --- a/chain/ring.go +++ b/chain/ring.go @@ -56,8 +56,8 @@ func (c *Chain) GetRingOutputs(height, amount uint64, offsets []uint64) ([]types // before or after the contract expiration. The refund path only opens after // the expiration height has passed. func ringOutputSpendKey(height uint64, target types.TxOutTarget) (types.PublicKey, error) { - if t, ok := types.AsTxOutToKey(target); ok { - return t.Key, nil + if key, ok := (types.TxOutputBare{Target: target}).SpendKey(); ok { + return key, nil } switch t := target.(type) { diff --git a/tui/explorer_model.go b/tui/explorer_model.go index 31dce3d..94b7046 100644 --- a/tui/explorer_model.go +++ b/tui/explorer_model.go @@ -325,8 +325,8 @@ func (m *ExplorerModel) viewTxDetail() string { for i, output := range tx.Vout { switch v := output.(type) { case types.TxOutputBare: - 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])) + if targetKey, ok := v.SpendKey(); ok { + b.WriteString(fmt.Sprintf(" [%d] bare amount=%d key=%x\n", i, v.Amount, targetKey[: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 7c0ea1d..2b90b0f 100644 --- a/types/transaction.go +++ b/types/transaction.go @@ -244,6 +244,17 @@ type TxOutputBare struct { Target TxOutTarget } +// SpendKey returns the standard transparent spend key when the target is +// TxOutToKey. Callers that only care about transparent key outputs can use +// this instead of repeating a type assertion. +func (t TxOutputBare) SpendKey() (PublicKey, bool) { + target, ok := AsTxOutToKey(t.Target) + if !ok { + return PublicKey{}, false + } + return target.Key, true +} + // OutputType returns the wire variant tag for bare outputs. func (t TxOutputBare) OutputType() uint8 { return OutputTypeBare } diff --git a/types/transaction_test.go b/types/transaction_test.go index 166f2d3..ac38d0e 100644 --- a/types/transaction_test.go +++ b/types/transaction_test.go @@ -33,6 +33,27 @@ func TestAsTxOutToKey_Bad(t *testing.T) { } } +func TestTxOutputBare_SpendKey_Good(t *testing.T) { + out := TxOutputBare{ + Amount: 10, + Target: TxOutToKey{Key: PublicKey{0xAA, 0xBB}, MixAttr: 3}, + } + key, ok := out.SpendKey() + if !ok { + t.Fatal("SpendKey: expected true for TxOutToKey target") + } + if key != (PublicKey{0xAA, 0xBB}) { + t.Errorf("SpendKey: got %x, want %x", key, PublicKey{0xAA, 0xBB}) + } +} + +func TestTxOutputBare_SpendKey_Bad(t *testing.T) { + out := TxOutputBare{Target: TxOutHTLC{Expiration: 100}} + if key, ok := out.SpendKey(); ok || key != (PublicKey{}) { + t.Fatalf("SpendKey: got (%x, %v), want zero key and false", key, ok) + } +} + 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 8cc36aa..955b153 100644 --- a/wallet/scanner.go +++ b/wallet/scanner.go @@ -64,11 +64,11 @@ func (s *V1Scanner) ScanTransaction(tx *types.Transaction, txHash types.Hash, continue } - targetKey, ok := types.AsTxOutToKey(bare.Target) + targetKey, ok := bare.SpendKey() if !ok { continue } - if types.PublicKey(expectedPublicKey) != targetKey.Key { + if types.PublicKey(expectedPublicKey) != targetKey { continue }