github.com/decred/dcrlnd@v0.7.6/watchtower/blob/type.go (about)

     1  package blob
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  )
     7  
     8  // Flag represents a specify option that can be present in a Type.
     9  type Flag uint16
    10  
    11  const (
    12  	// FlagReward signals that the justice transaction should contain an
    13  	// additional output for itself. Signatures sent by the client should
    14  	// include the reward script negotiated during session creation. Without
    15  	// the flag, there is only one output sweeping clients funds back to
    16  	// them solely.
    17  	FlagReward Flag = 1
    18  
    19  	// FlagCommitOutputs signals that the blob contains the information
    20  	// required to sweep commitment outputs.
    21  	FlagCommitOutputs Flag = 1 << 1
    22  
    23  	// FlagAnchorChannel signals that this blob is meant to spend an anchor
    24  	// channel, and therefore must expect a P2WSH-style to-remote output if
    25  	// one exists.
    26  	FlagAnchorChannel Flag = 1 << 2
    27  )
    28  
    29  // Type returns a Type consisting solely of this flag enabled.
    30  func (f Flag) Type() Type {
    31  	return Type(f)
    32  }
    33  
    34  // String returns the name of the flag.
    35  func (f Flag) String() string {
    36  	switch f {
    37  	case FlagReward:
    38  		return "FlagReward"
    39  	case FlagCommitOutputs:
    40  		return "FlagCommitOutputs"
    41  	case FlagAnchorChannel:
    42  		return "FlagAnchorChannel"
    43  	default:
    44  		return "FlagUnknown"
    45  	}
    46  }
    47  
    48  // Type is a bit vector composed of Flags that govern various aspects of
    49  // reconstructing the justice transaction from an encrypted blob. The flags can
    50  // be used to signal behaviors such as which inputs are being swept, which
    51  // outputs should be added to the justice transaction, or modify serialization
    52  // of the blob itself.
    53  type Type uint16
    54  
    55  const (
    56  	// TypeAltruistCommit sweeps only commitment outputs to a sweep address
    57  	// controlled by the user, and does not give the tower a reward.
    58  	TypeAltruistCommit = Type(FlagCommitOutputs)
    59  
    60  	// TypeAltruistAnchorCommit sweeps only commitment outputs from an
    61  	// anchor commitment to a sweep address controlled by the user, and does
    62  	// not give the tower a reward.
    63  	TypeAltruistAnchorCommit = Type(FlagCommitOutputs | FlagAnchorChannel)
    64  
    65  	// TypeRewardCommit sweeps only commitment outputs to a sweep address
    66  	// controlled by the user, and pays a negotiated reward to the tower.
    67  	TypeRewardCommit = Type(FlagCommitOutputs | FlagReward)
    68  )
    69  
    70  // Has returns true if the Type has the passed flag enabled.
    71  func (t Type) Has(flag Flag) bool {
    72  	return Flag(t)&flag == flag
    73  }
    74  
    75  // TypeFromFlags creates a single Type from an arbitrary list of flags.
    76  func TypeFromFlags(flags ...Flag) Type {
    77  	var typ Type
    78  	for _, flag := range flags {
    79  		typ |= Type(flag)
    80  	}
    81  
    82  	return typ
    83  }
    84  
    85  // IsAnchorChannel returns true if the blob type is for an anchor channel.
    86  func (t Type) IsAnchorChannel() bool {
    87  	return t.Has(FlagAnchorChannel)
    88  }
    89  
    90  // knownFlags maps the supported flags to their name.
    91  var knownFlags = map[Flag]struct{}{
    92  	FlagReward:        {},
    93  	FlagCommitOutputs: {},
    94  	FlagAnchorChannel: {},
    95  }
    96  
    97  // String returns a human readable description of a Type.
    98  func (t Type) String() string {
    99  	var (
   100  		hrPieces        []string
   101  		hasUnknownFlags bool
   102  	)
   103  
   104  	// Iterate through the possible flags from highest to lowest. This will
   105  	// ensure that the human readable names will be in the same order as the
   106  	// bits (left to right) if the type were to be printed in big-endian
   107  	// byte order.
   108  	for f := Flag(1 << 15); f != 0; f >>= 1 {
   109  		// If this flag is known, we'll add a human-readable name or its
   110  		// inverse depending on whether the type has this flag set.
   111  		if _, ok := knownFlags[f]; ok {
   112  			if t.Has(f) {
   113  				hrPieces = append(hrPieces, f.String())
   114  			} else {
   115  				hrPieces = append(hrPieces, "No-"+f.String())
   116  			}
   117  		} else {
   118  			// Make note of any unknown flags that this type has
   119  			// set. If any are present, we'll prepend the bit-wise
   120  			// representation of the type in the final string.
   121  			if t.Has(f) {
   122  				hasUnknownFlags = true
   123  			}
   124  		}
   125  	}
   126  
   127  	// If there were no unknown flags, we'll simply return the list of human
   128  	// readable pieces.
   129  	if !hasUnknownFlags {
   130  		return fmt.Sprintf("[%s]", strings.Join(hrPieces, "|"))
   131  	}
   132  
   133  	// Otherwise, we'll prepend the bit-wise representation to the human
   134  	// readable names.
   135  	return fmt.Sprintf("%016b[%s]", t, strings.Join(hrPieces, "|"))
   136  }
   137  
   138  // supportedTypes is the set of all configurations known to be supported by the
   139  // package.
   140  var supportedTypes = map[Type]struct{}{
   141  	TypeAltruistCommit:       {},
   142  	TypeRewardCommit:         {},
   143  	TypeAltruistAnchorCommit: {},
   144  }
   145  
   146  // IsSupportedType returns true if the given type is supported by the package.
   147  func IsSupportedType(blobType Type) bool {
   148  	_, ok := supportedTypes[blobType]
   149  	return ok
   150  }
   151  
   152  // SupportedTypes returns a list of all supported blob types.
   153  func SupportedTypes() []Type {
   154  	supported := make([]Type, 0, len(supportedTypes))
   155  	for t := range supportedTypes {
   156  		supported = append(supported, t)
   157  	}
   158  	return supported
   159  }