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 &{ 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 }