Skip to content

Commit eea552e

Browse files
committed
proof: add SendFragment and SendFragmentEnvelope types
1 parent ffd93a8 commit eea552e

File tree

4 files changed

+466
-0
lines changed

4 files changed

+466
-0
lines changed

proof/encoding.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,139 @@ func VersionDecoder(r io.Reader, val any, buf *[8]byte, l uint64) error {
6464
return tlv.NewTypeForDecodingErr(val, "TransitionVersion", l, 1)
6565
}
6666

67+
func FragmentVersionEncoder(w io.Writer, val any, buf *[8]byte) error {
68+
if t, ok := val.(*SendFragmentVersion); ok {
69+
return tlv.EUint8T(w, uint8(*t), buf)
70+
}
71+
return tlv.NewTypeForEncodingErr(val, "SendFragmentVersion")
72+
}
73+
74+
func FragmentVersionDecoder(r io.Reader, val any, buf *[8]byte,
75+
l uint64) error {
76+
77+
if typ, ok := val.(*SendFragmentVersion); ok {
78+
var t uint8
79+
if err := tlv.DUint8(r, &t, buf, l); err != nil {
80+
return err
81+
}
82+
*typ = SendFragmentVersion(t)
83+
return nil
84+
}
85+
return tlv.NewTypeForDecodingErr(val, "SendFragmentVersion", l, 1)
86+
}
87+
88+
func SendOutputEncoder(w io.Writer, val any, buf *[8]byte) error {
89+
if t, ok := val.(*SendOutput); ok {
90+
err := tlv.EUint8T(w, uint8(t.AssetVersion), buf)
91+
if err != nil {
92+
return err
93+
}
94+
if err := tlv.EUint64T(w, t.Amount, buf); err != nil {
95+
return err
96+
}
97+
err = tlv.EUint8T(w, uint8(t.DerivationMethod), buf)
98+
if err != nil {
99+
return err
100+
}
101+
102+
keyArr := ([btcec.PubKeyBytesLenCompressed]byte)(t.ScriptKey)
103+
return tlv.EBytes33(w, &keyArr, buf)
104+
}
105+
return tlv.NewTypeForEncodingErr(val, "*SendOutput")
106+
}
107+
108+
func SendOutputDecoder(r io.Reader, val any, buf *[8]byte) error {
109+
if typ, ok := val.(*SendOutput); ok {
110+
var assetVersion uint8
111+
if err := tlv.DUint8(r, &assetVersion, buf, 1); err != nil {
112+
return err
113+
}
114+
typ.AssetVersion = asset.Version(assetVersion)
115+
116+
if err := tlv.DUint64(r, &typ.Amount, buf, 8); err != nil {
117+
return err
118+
}
119+
120+
var derivationMethod uint8
121+
if err := tlv.DUint8(r, &derivationMethod, buf, 1); err != nil {
122+
return err
123+
}
124+
typ.DerivationMethod = asset.ScriptKeyDerivationMethod(
125+
derivationMethod,
126+
)
127+
128+
keyArr := ([btcec.PubKeyBytesLenCompressed]byte)(typ.ScriptKey)
129+
if err := tlv.DBytes33(
130+
r, &keyArr, buf, btcec.PubKeyBytesLenCompressed,
131+
); err != nil {
132+
return err
133+
}
134+
typ.ScriptKey = keyArr
135+
136+
return nil
137+
}
138+
return tlv.NewTypeForEncodingErr(val, "*SendOutput")
139+
}
140+
141+
func SendOutputsEncoder(w io.Writer, val any, buf *[8]byte) error {
142+
if t, ok := val.(*map[asset.ID]SendOutput); ok {
143+
numOutputs := uint64(len(*t))
144+
if err := tlv.WriteVarInt(w, numOutputs, buf); err != nil {
145+
return err
146+
}
147+
148+
for id, output := range *t {
149+
idArr := ([32]byte)(id)
150+
if err := tlv.EBytes32(w, &idArr, buf); err != nil {
151+
return err
152+
}
153+
154+
err := SendOutputEncoder(w, &output, buf)
155+
if err != nil {
156+
return err
157+
}
158+
}
159+
return nil
160+
}
161+
return tlv.NewTypeForEncodingErr(val, "map[asset.ID]SendOutput")
162+
}
163+
164+
func SendOutputsDecoder(r io.Reader, val any, buf *[8]byte, l uint64) error {
165+
if typ, ok := val.(*map[asset.ID]SendOutput); ok {
166+
numOutputs, err := tlv.ReadVarInt(r, buf)
167+
if err != nil {
168+
return err
169+
}
170+
171+
// Avoid OOM by limiting the number of send outputs we accept.
172+
if numOutputs > MaxSendFragmentOutputs {
173+
return fmt.Errorf("%w: too many send outputs",
174+
ErrProofInvalid)
175+
}
176+
177+
result := make(map[asset.ID]SendOutput, numOutputs)
178+
for i := uint64(0); i < numOutputs; i++ {
179+
var id [32]byte
180+
if err := tlv.DBytes32(r, &id, buf, 32); err != nil {
181+
return err
182+
}
183+
184+
var output SendOutput
185+
err := SendOutputDecoder(r, &output, buf)
186+
if err != nil {
187+
return err
188+
}
189+
190+
result[id] = output
191+
}
192+
193+
*typ = result
194+
195+
return nil
196+
}
197+
return tlv.NewTypeForEncodingErr(val, "map[asset.ID]SendOutput")
198+
}
199+
67200
func BlockHeaderEncoder(w io.Writer, val any, buf *[8]byte) error {
68201
if t, ok := val.(*wire.BlockHeader); ok {
69202
return t.Serialize(w)

proof/records.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ const (
5454
MetaRevealUniverseCommitments tlv.Type = 7
5555
MetaRevealCanonicalUniversesType tlv.Type = 9
5656
MetaRevealDelegationKeyType tlv.Type = 11
57+
58+
SendFragmentVersionType tlv.Type = 0
59+
SendFragmentBlockHeaderType tlv.Type = 2
60+
SendFragmentBlockHeightType tlv.Type = 4
61+
SendFragmentOutPointType tlv.Type = 6
62+
SendFragmentOutputsType tlv.Type = 8
5763
)
5864

5965
// KnownProofTypes is a set of all known proof TLV types. This set is asserted
@@ -97,12 +103,64 @@ var KnownMetaRevealTypes = fn.NewSet(
97103
MetaRevealDelegationKeyType,
98104
)
99105

106+
// KnownSendFragmentTypes is a set of all known send fragment TLV types.
107+
// This set is asserted to be complete by a check in the BIP test vector unit
108+
// tests.
109+
var KnownSendFragmentTypes = fn.NewSet(
110+
SendFragmentVersionType, SendFragmentBlockHeaderType,
111+
SendFragmentBlockHeightType, SendFragmentOutPointType,
112+
SendFragmentOutputsType,
113+
)
114+
100115
func VersionRecord(version *TransitionVersion) tlv.Record {
101116
return tlv.MakeStaticRecord(
102117
VersionType, version, 4, VersionEncoder, VersionDecoder,
103118
)
104119
}
105120

121+
func FragmentVersionRecord(version *SendFragmentVersion) tlv.Record {
122+
return tlv.MakeStaticRecord(
123+
SendFragmentVersionType, version, 1, FragmentVersionEncoder,
124+
FragmentVersionDecoder,
125+
)
126+
}
127+
128+
func FragmentBlockHeaderRecord(header *wire.BlockHeader) tlv.Record {
129+
return tlv.MakeStaticRecord(
130+
SendFragmentBlockHeaderType, header, wire.MaxBlockHeaderPayload,
131+
BlockHeaderEncoder, BlockHeaderDecoder,
132+
)
133+
}
134+
135+
func FragmentBlockHeightRecord(height *uint32) tlv.Record {
136+
return tlv.MakeStaticRecord(
137+
SendFragmentBlockHeightType, height, 4, tlv.EUint32,
138+
tlv.DUint32,
139+
)
140+
}
141+
142+
func FragmentOutPointRecord(prevOut *wire.OutPoint) tlv.Record {
143+
return tlv.MakeStaticRecord(
144+
SendFragmentOutPointType, prevOut, 32+4, asset.OutPointEncoder,
145+
asset.OutPointDecoder,
146+
)
147+
}
148+
149+
func FragmentOutputsRecord(outputs *map[asset.ID]SendOutput) tlv.Record {
150+
sizeFunc := func() uint64 {
151+
var buf bytes.Buffer
152+
err := SendOutputsEncoder(&buf, outputs, &[8]byte{})
153+
if err != nil {
154+
panic(err)
155+
}
156+
return uint64(len(buf.Bytes()))
157+
}
158+
return tlv.MakeDynamicRecord(
159+
SendFragmentOutputsType, outputs, sizeFunc, SendOutputsEncoder,
160+
SendOutputsDecoder,
161+
)
162+
}
163+
106164
func PrevOutRecord(prevOut *wire.OutPoint) tlv.Record {
107165
return tlv.MakeStaticRecord(
108166
PrevOutType, prevOut, 32+4, asset.OutPointEncoder,

0 commit comments

Comments
 (0)