github.com/decred/dcrlnd@v0.7.6/record/amp.go (about)

     1  package record
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/decred/dcrlnd/tlv"
     8  )
     9  
    10  // AMPOnionType is the type used in the onion to reference the AMP fields:
    11  // root_share, set_id, and child_index.
    12  const AMPOnionType tlv.Type = 14
    13  
    14  // AMP is a record that encodes the fields necessary for atomic multi-path
    15  // payments.
    16  type AMP struct {
    17  	rootShare  [32]byte
    18  	setID      [32]byte
    19  	childIndex uint32
    20  }
    21  
    22  // NewAMP generate a new AMP record with the given root_share, set_id, and
    23  // child_index.
    24  func NewAMP(rootShare, setID [32]byte, childIndex uint32) *AMP {
    25  	return &AMP{
    26  		rootShare:  rootShare,
    27  		setID:      setID,
    28  		childIndex: childIndex,
    29  	}
    30  }
    31  
    32  // RootShare returns the root share contained in the AMP record.
    33  func (a *AMP) RootShare() [32]byte {
    34  	return a.rootShare
    35  }
    36  
    37  // SetID returns the set id contained in the AMP record.
    38  func (a *AMP) SetID() [32]byte {
    39  	return a.setID
    40  }
    41  
    42  // ChildIndex returns the child index contained in the AMP record.
    43  func (a *AMP) ChildIndex() uint32 {
    44  	return a.childIndex
    45  }
    46  
    47  // AMPEncoder writes the AMP record to the provided io.Writer.
    48  func AMPEncoder(w io.Writer, val interface{}, buf *[8]byte) error {
    49  	if v, ok := val.(*AMP); ok {
    50  		if err := tlv.EBytes32(w, &v.rootShare, buf); err != nil {
    51  			return err
    52  		}
    53  
    54  		if err := tlv.EBytes32(w, &v.setID, buf); err != nil {
    55  			return err
    56  		}
    57  
    58  		return tlv.ETUint32T(w, v.childIndex, buf)
    59  	}
    60  	return tlv.NewTypeForEncodingErr(val, "AMP")
    61  }
    62  
    63  const (
    64  	// minAMPLength is the minimum length of a serialized AMP TLV record,
    65  	// which occurs when the truncated encoding of child_index takes 0
    66  	// bytes, leaving only the root_share and set_id.
    67  	minAMPLength = 64
    68  
    69  	// maxAMPLength is the maximum legnth of a serialized AMP TLV record,
    70  	// which occurs when the truncated endoing of a child_index takes 2
    71  	// bytes.
    72  	maxAMPLength = 68
    73  )
    74  
    75  // AMPDecoder reads the AMP record from the provided io.Reader.
    76  func AMPDecoder(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
    77  	if v, ok := val.(*AMP); ok && minAMPLength <= l && l <= maxAMPLength {
    78  		if err := tlv.DBytes32(r, &v.rootShare, buf, 32); err != nil {
    79  			return err
    80  		}
    81  
    82  		if err := tlv.DBytes32(r, &v.setID, buf, 32); err != nil {
    83  			return err
    84  		}
    85  
    86  		return tlv.DTUint32(r, &v.childIndex, buf, l-minAMPLength)
    87  	}
    88  	return tlv.NewTypeForDecodingErr(val, "AMP", l, maxAMPLength)
    89  }
    90  
    91  // Record returns a tlv.Record that can be used to encode or decode this record.
    92  func (a *AMP) Record() tlv.Record {
    93  	return tlv.MakeDynamicRecord(
    94  		AMPOnionType, a, a.PayloadSize, AMPEncoder, AMPDecoder,
    95  	)
    96  }
    97  
    98  // PayloadSize returns the size this record takes up in encoded form.
    99  func (a *AMP) PayloadSize() uint64 {
   100  	return 32 + 32 + tlv.SizeTUint32(a.childIndex)
   101  }
   102  
   103  // String returns a human-readble description of the amp payload fields.
   104  func (a *AMP) String() string {
   105  	if a == nil {
   106  		return "<nil>"
   107  	}
   108  
   109  	return fmt.Sprintf("root_share=%x set_id=%x child_index=%d",
   110  		a.rootShare, a.setID, a.childIndex)
   111  }