1// SPDX-License-Identifier: ISC
2// Copyright (c) 2014-2020 Bitmark Inc.
3// Use of this source code is governed by an ISC
4// license that can be found in the LICENSE file.
5
6package transactionrecord
7
8import (
9	"github.com/bitmark-inc/bitmarkd/account"
10	"github.com/bitmark-inc/bitmarkd/currency"
11	"github.com/bitmark-inc/bitmarkd/fault"
12	"github.com/bitmark-inc/bitmarkd/merkle"
13	"github.com/bitmark-inc/bitmarkd/util"
14)
15
16// Unpack - turn a byte slice into a record
17// Note: the unpacker will access the underlying array of the packed
18//       record so p[x:y].Unpack() can read past p[y] and couldcontinue up to cap(p)
19//       i.e p[x:cap(p)].Unpack() performs the same operation
20//       elements beefore p[x] cannot be accessed
21//       see: https://blog.golang.org/go-slices-usage-and-internals
22//
23// must cast result to correct type
24//
25// e.g.
26//   registration, ok := result.(*transaction.Registration)
27// or:
28//   switch tx := result.(type) {
29//   case *transaction.Registration:
30func (record Packed) Unpack(testnet bool) (t Transaction, n int, e error) {
31
32	defer func() {
33		if r := recover(); nil != r {
34			e = fault.NotTransactionPack
35		}
36	}()
37
38	recordType, n := util.ClippedVarint64(record, 1, 8192)
39	if 0 == n {
40		return nil, 0, fault.NotTransactionPack
41	}
42
43unpack_switch:
44	switch TagType(recordType) {
45
46	case BaseDataTag:
47
48		// currency
49		c, currencyLength := util.FromVarint64(record[n:])
50		if 0 == currencyLength {
51			break unpack_switch
52		}
53		n += currencyLength
54		currency, err := currency.FromUint64(c)
55		if nil != err {
56			return nil, 0, err
57		}
58
59		// paymentAddress
60		paymentAddressLength, paymentAddressOffset := util.ClippedVarint64(record[n:], 1, 8192)
61		if 0 == paymentAddressOffset {
62			break unpack_switch
63		}
64		n += paymentAddressOffset
65		paymentAddress := string(record[n : n+paymentAddressLength])
66		n += paymentAddressLength
67
68		// owner public key
69		ownerLength, ownerOffset := util.ClippedVarint64(record[n:], 1, 8192)
70		if 0 == ownerOffset {
71			break unpack_switch
72		}
73		n += ownerOffset
74		owner, err := account.AccountFromBytes(record[n : n+ownerLength])
75		if nil != err {
76			return nil, 0, err
77		}
78		if owner.IsTesting() != testnet {
79			return nil, 0, fault.WrongNetworkForPublicKey
80		}
81		n += ownerLength
82
83		// nonce
84		nonce, nonceLength := util.FromVarint64(record[n:])
85		if 0 == nonceLength {
86			break unpack_switch
87		}
88		n += nonceLength
89
90		// signature is remainder of record
91		signatureLength, signatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
92		if 0 == signatureOffset {
93			break unpack_switch
94		}
95		signature := make(account.Signature, signatureLength)
96		n += signatureOffset
97		copy(signature, record[n:n+signatureLength])
98		n += signatureLength
99
100		r := &OldBaseData{
101			Owner:          owner,
102			Currency:       currency,
103			PaymentAddress: string(paymentAddress),
104			Nonce:          nonce,
105			Signature:      signature,
106		}
107		err = r.check(testnet)
108		if nil != err {
109			return nil, 0, err
110		}
111		return r, n, nil
112
113	case AssetDataTag:
114
115		// name
116		nameLength, nameOffset := util.ClippedVarint64(record[n:], 0, 8192)
117
118		name := make([]byte, nameLength)
119		n += nameOffset
120		copy(name, record[n:n+nameLength])
121		n += nameLength
122
123		// fingerprint
124		fingerprintLength, fingerprintOffset := util.ClippedVarint64(record[n:], 1, 8192)
125		if 0 == fingerprintOffset {
126			break unpack_switch
127		}
128		fingerprint := make([]byte, fingerprintLength)
129		n += fingerprintOffset
130		copy(fingerprint, record[n:n+fingerprintLength])
131		n += fingerprintLength
132
133		// metadata (can be zero length)
134		metadataLength, metadataOffset := util.ClippedVarint64(record[n:], 0, 8192) // Note: zero is valid here
135		if 0 == metadataOffset {
136			break unpack_switch
137		}
138		metadata := make([]byte, metadataLength)
139		n += metadataOffset
140		copy(metadata, record[n:n+metadataLength])
141		n += metadataLength
142
143		// registrant public key
144		registrantLength, registrantOffset := util.ClippedVarint64(record[n:], 1, 8192)
145		if 0 == registrantOffset {
146			break unpack_switch
147		}
148		n += registrantOffset
149		registrant, err := account.AccountFromBytes(record[n : n+registrantLength])
150		if nil != err {
151			return nil, 0, err
152		}
153		if registrant.IsTesting() != testnet {
154			return nil, 0, fault.WrongNetworkForPublicKey
155		}
156		n += registrantLength
157
158		// signature is remainder of record
159		signatureLength, signatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
160		if 0 == signatureOffset {
161			break unpack_switch
162		}
163		signature := make(account.Signature, signatureLength)
164		n += signatureOffset
165		copy(signature, record[n:n+signatureLength])
166		n += signatureLength
167
168		r := &AssetData{
169			Name:        string(name),
170			Fingerprint: string(fingerprint),
171			Metadata:    string(metadata),
172			Registrant:  registrant,
173			Signature:   signature,
174		}
175		err = r.check(testnet)
176		if nil != err {
177			return nil, 0, err
178		}
179		return r, n, nil
180
181	case BitmarkIssueTag:
182
183		// asset id
184		assetIdentifierLength, assetIdentifierOffset := util.ClippedVarint64(record[n:], 1, 8192)
185		if 0 == assetIdentifierOffset {
186			break unpack_switch
187		}
188		n += assetIdentifierOffset
189		var assetId AssetIdentifier
190		err := AssetIdentifierFromBytes(&assetId, record[n:n+assetIdentifierLength])
191		if nil != err {
192			return nil, 0, err
193		}
194		n += assetIdentifierLength
195
196		// owner public key
197		ownerLength, ownerOffset := util.ClippedVarint64(record[n:], 1, 8192)
198		if 0 == ownerOffset {
199			break unpack_switch
200		}
201		n += ownerOffset
202		owner, err := account.AccountFromBytes(record[n : n+ownerLength])
203		if nil != err {
204			return nil, 0, err
205		}
206		if owner.IsTesting() != testnet {
207			return nil, 0, fault.WrongNetworkForPublicKey
208		}
209		n += ownerLength
210
211		// nonce
212		nonce, nonceLength := util.FromVarint64(record[n:])
213		if 0 == nonceLength {
214			break unpack_switch
215		}
216		n += nonceLength
217
218		// signature is remainder of record
219		signatureLength, signatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
220		if 0 == signatureOffset {
221			break unpack_switch
222		}
223		signature := make(account.Signature, signatureLength)
224		n += signatureOffset
225		copy(signature, record[n:n+signatureLength])
226		n += signatureLength
227
228		r := &BitmarkIssue{
229			AssetId:   assetId,
230			Owner:     owner,
231			Signature: signature,
232			Nonce:     nonce,
233		}
234		err = r.check(testnet)
235		if nil != err {
236			return nil, 0, err
237		}
238		return r, n, nil
239
240	case BitmarkTransferUnratifiedTag:
241
242		// link
243		linkLength, linkOffset := util.ClippedVarint64(record[n:], 1, 8192)
244		if 0 == linkOffset {
245			break unpack_switch
246		}
247		n += linkOffset
248		var link merkle.Digest
249		err := merkle.DigestFromBytes(&link, record[n:n+linkLength])
250		if nil != err {
251			return nil, 0, err
252		}
253		n += linkLength
254
255		// optional escrow payment
256		escrow, n, err := unpackEscrow(record, n)
257		if nil != err {
258			return nil, 0, err
259		}
260
261		// owner public key
262		ownerLength, ownerOffset := util.ClippedVarint64(record[n:], 1, 8192)
263		if 0 == ownerOffset {
264			break unpack_switch
265		}
266		n += ownerOffset
267		owner, err := account.AccountFromBytes(record[n : n+ownerLength])
268		if nil != err {
269			return nil, 0, err
270		}
271		if owner.IsTesting() != testnet {
272			return nil, 0, fault.WrongNetworkForPublicKey
273		}
274		n += ownerLength
275
276		// signature is remainder of record
277		signatureLength, signatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
278		if 0 == signatureOffset {
279			break unpack_switch
280		}
281		signature := make(account.Signature, signatureLength)
282		n += signatureOffset
283		copy(signature, record[n:n+signatureLength])
284		n += signatureLength
285
286		r := &BitmarkTransferUnratified{
287			Link:      link,
288			Escrow:    escrow,
289			Owner:     owner,
290			Signature: signature,
291		}
292		err = r.check(testnet)
293		if nil != err {
294			return nil, 0, err
295		}
296		return r, n, nil
297
298	case BitmarkTransferCountersignedTag:
299
300		// link
301		linkLength, linkOffset := util.ClippedVarint64(record[n:], 1, 8192)
302		if 0 == linkOffset {
303			break unpack_switch
304		}
305		n += linkOffset
306		var link merkle.Digest
307		err := merkle.DigestFromBytes(&link, record[n:n+linkLength])
308		if nil != err {
309			return nil, 0, err
310		}
311		n += linkLength
312
313		// optional escrow payment
314		escrow, n, err := unpackEscrow(record, n)
315		if nil != err {
316			return nil, 0, err
317		}
318
319		// owner public key
320		ownerLength, ownerOffset := util.ClippedVarint64(record[n:], 1, 8192)
321		if 0 == ownerOffset {
322			break unpack_switch
323		}
324		n += ownerOffset
325		owner, err := account.AccountFromBytes(record[n : n+ownerLength])
326		if nil != err {
327			return nil, 0, err
328		}
329		if owner.IsTesting() != testnet {
330			return nil, 0, fault.WrongNetworkForPublicKey
331		}
332		n += ownerLength
333
334		// signature
335		signatureLength, signatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
336		if 0 == signatureOffset {
337			break unpack_switch
338		}
339		signature := make(account.Signature, signatureLength)
340		n += signatureOffset
341		copy(signature, record[n:n+signatureLength])
342		n += signatureLength
343
344		// countersignature
345		countersignatureLength, countersignatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
346		if 0 == countersignatureOffset {
347			break unpack_switch
348		}
349		countersignature := make(account.Signature, countersignatureLength)
350		n += countersignatureOffset
351		copy(countersignature, record[n:n+countersignatureLength])
352		n += countersignatureLength
353
354		r := &BitmarkTransferCountersigned{
355			Link:             link,
356			Escrow:           escrow,
357			Owner:            owner,
358			Signature:        signature,
359			Countersignature: countersignature,
360		}
361		err = r.check(testnet)
362		if nil != err {
363			return nil, 0, err
364		}
365		return r, n, nil
366
367	case BlockFoundationTag:
368
369		// version
370		version, versionLength := util.FromVarint64(record[n:])
371		if 0 == versionLength {
372			break unpack_switch
373		}
374		n += versionLength
375		if version < 1 || version >= uint64(len(versions)) {
376			return nil, 0, fault.InvalidCurrencyAddress // ***** FIX THIS: is this error right?
377		}
378
379		// payment map
380		paymentsLength, paymentsOffset := util.ClippedVarint64(record[n:], 1, 8192)
381		if 0 == paymentsOffset {
382			break unpack_switch
383		}
384		n += paymentsOffset
385		payments, cs, err := currency.UnpackMap(record[n:n+paymentsLength], testnet)
386		if nil != err {
387			return nil, 0, err
388		}
389		if cs != versions[version] {
390			return nil, 0, fault.InvalidCurrencyAddress // ***** FIX THIS: is this error right?
391		}
392		n += paymentsLength
393
394		// owner public key
395		ownerLength, ownerOffset := util.ClippedVarint64(record[n:], 1, 8192)
396		if 0 == ownerOffset {
397			break unpack_switch
398		}
399		n += ownerOffset
400		owner, err := account.AccountFromBytes(record[n : n+ownerLength])
401		if nil != err {
402			return nil, 0, err
403		}
404		if owner.IsTesting() != testnet {
405			return nil, 0, fault.WrongNetworkForPublicKey
406		}
407		n += ownerLength
408
409		// nonce
410		nonce, nonceLength := util.FromVarint64(record[n:])
411		if 0 == nonceLength {
412			break unpack_switch
413		}
414		n += nonceLength
415
416		// signature is remainder of record
417		signatureLength, signatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
418		if 0 == signatureOffset {
419			break unpack_switch
420		}
421		signature := make(account.Signature, signatureLength)
422		n += signatureOffset
423		copy(signature, record[n:n+signatureLength])
424		n += signatureLength
425
426		r := &BlockFoundation{
427			Version:   version,
428			Owner:     owner,
429			Payments:  payments,
430			Nonce:     nonce,
431			Signature: signature,
432		}
433		err = r.check(testnet)
434		if nil != err {
435			return nil, 0, err
436		}
437		return r, n, nil
438
439	case BlockOwnerTransferTag:
440
441		// link
442		linkLength, linkOffset := util.ClippedVarint64(record[n:], 1, 8192)
443		if 0 == linkOffset {
444			break unpack_switch
445		}
446		n += linkOffset
447		var link merkle.Digest
448		err := merkle.DigestFromBytes(&link, record[n:n+linkLength])
449		if nil != err {
450			return nil, 0, err
451		}
452		n += linkLength
453
454		// optional escrow payment
455		escrow, n, err := unpackEscrow(record, n)
456		if nil != err {
457			return nil, 0, err
458		}
459
460		// version
461		version, versionLength := util.FromVarint64(record[n:])
462		if 0 == versionLength {
463			break unpack_switch
464		}
465		n += versionLength
466		if version < 1 || version >= uint64(len(versions)) {
467			return nil, 0, fault.InvalidCurrencyAddress // ***** FIX THIS: is this error right?
468		}
469
470		// payment map
471
472		paymentsLength, paymentsOffset := util.ClippedVarint64(record[n:], 1, 8192)
473		if 0 == paymentsOffset {
474			break unpack_switch
475		}
476		n += paymentsOffset
477		payments, cs, err := currency.UnpackMap(record[n:n+paymentsLength], testnet)
478		if nil != err {
479			return nil, 0, err
480		}
481		if cs != versions[version] {
482			return nil, 0, fault.InvalidCurrencyAddress // ***** FIX THIS: is this error right?
483		}
484		n += paymentsLength
485
486		// owner public key
487		ownerLength, ownerOffset := util.ClippedVarint64(record[n:], 1, 8192)
488		if 0 == ownerOffset {
489			break unpack_switch
490		}
491		n += ownerOffset
492		owner, err := account.AccountFromBytes(record[n : n+ownerLength])
493		if nil != err {
494			return nil, 0, err
495		}
496		if owner.IsTesting() != testnet {
497			return nil, 0, fault.WrongNetworkForPublicKey
498		}
499		n += ownerLength
500
501		// signature
502		signatureLength, signatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
503		if 0 == signatureOffset {
504			break unpack_switch
505		}
506		signature := make(account.Signature, signatureLength)
507		n += signatureOffset
508		copy(signature, record[n:n+signatureLength])
509		n += signatureLength
510
511		// countersignature
512		countersignatureLength, countersignatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
513		if 0 == countersignatureOffset {
514			break unpack_switch
515		}
516		countersignature := make(account.Signature, countersignatureLength)
517		n += countersignatureOffset
518		copy(countersignature, record[n:n+countersignatureLength])
519		n += countersignatureLength
520
521		r := &BlockOwnerTransfer{
522			Link:             link,
523			Escrow:           escrow,
524			Version:          version,
525			Owner:            owner,
526			Payments:         payments,
527			Signature:        signature,
528			Countersignature: countersignature,
529		}
530		err = r.check(testnet)
531		if nil != err {
532			return nil, 0, err
533		}
534		return r, n, nil
535
536	case BitmarkShareTag:
537
538		// link
539		linkLength, linkOffset := util.ClippedVarint64(record[n:], 1, 8192)
540		if 0 == linkOffset {
541			break unpack_switch
542		}
543		n += linkOffset
544		var link merkle.Digest
545		err := merkle.DigestFromBytes(&link, record[n:n+linkLength])
546		if nil != err {
547			return nil, 0, err
548		}
549		n += linkLength
550
551		// total number of shares to issue
552		quantity, quantityLength := util.FromVarint64(record[n:])
553		if 0 == quantityLength {
554			break unpack_switch
555		}
556		n += quantityLength
557
558		// signature
559		signatureLength, signatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
560		if 0 == signatureOffset {
561			break unpack_switch
562		}
563		signature := make(account.Signature, signatureLength)
564		n += signatureOffset
565		copy(signature, record[n:n+signatureLength])
566		n += signatureLength
567
568		r := &BitmarkShare{
569			Link:      link,
570			Quantity:  quantity,
571			Signature: signature,
572		}
573		err = r.check(testnet)
574		if nil != err {
575			return nil, 0, err
576		}
577		return r, n, nil
578
579	case ShareGrantTag:
580
581		// share id
582		shareIdLength, shareIdOffset := util.ClippedVarint64(record[n:], 1, 8192)
583		if 0 == shareIdOffset {
584			break unpack_switch
585		}
586		n += shareIdOffset
587		var shareId merkle.Digest
588		err := merkle.DigestFromBytes(&shareId, record[n:n+shareIdLength])
589		if nil != err {
590			return nil, 0, err
591		}
592		n += shareIdLength
593
594		// number of shares to transfer
595		quantity, quantityLength := util.FromVarint64(record[n:])
596		if 0 == quantityLength {
597			break unpack_switch
598		}
599		n += quantityLength
600
601		// owner public key
602		ownerLength, ownerOffset := util.ClippedVarint64(record[n:], 1, 8192)
603		if 0 == ownerOffset {
604			break unpack_switch
605		}
606		n += ownerOffset
607		owner, err := account.AccountFromBytes(record[n : n+ownerLength])
608		if nil != err {
609			return nil, 0, err
610		}
611		if owner.IsTesting() != testnet {
612			return nil, 0, fault.WrongNetworkForPublicKey
613		}
614		n += ownerLength
615
616		// recipient public key
617		recipientLength, recipientOffset := util.ClippedVarint64(record[n:], 1, 8192)
618		if 0 == recipientOffset {
619			break unpack_switch
620		}
621		n += recipientOffset
622		recipient, err := account.AccountFromBytes(record[n : n+recipientLength])
623		if nil != err {
624			return nil, 0, err
625		}
626		if recipient.IsTesting() != testnet {
627			return nil, 0, fault.WrongNetworkForPublicKey
628		}
629		n += recipientLength
630
631		// time limit
632		beforeBlock, beforeBlockLength := util.FromVarint64(record[n:])
633		if 0 == beforeBlockLength {
634			break unpack_switch
635		}
636		n += beforeBlockLength
637
638		// signature
639		signatureLength, signatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
640		if 0 == signatureOffset {
641			break unpack_switch
642		}
643		signature := make(account.Signature, signatureLength)
644		n += signatureOffset
645		copy(signature, record[n:n+signatureLength])
646		n += signatureLength
647
648		// countersignature
649		countersignatureLength, countersignatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
650		if 0 == countersignatureOffset {
651			break unpack_switch
652		}
653		countersignature := make(account.Signature, countersignatureLength)
654		n += countersignatureOffset
655		copy(countersignature, record[n:n+countersignatureLength])
656		n += countersignatureLength
657
658		r := &ShareGrant{
659			ShareId:          shareId,
660			Quantity:         quantity,
661			Owner:            owner,
662			Recipient:        recipient,
663			BeforeBlock:      beforeBlock,
664			Signature:        signature,
665			Countersignature: countersignature,
666		}
667		err = r.check(testnet)
668		if nil != err {
669			return nil, 0, err
670		}
671		return r, n, nil
672
673	case ShareSwapTag:
674
675		// share one
676		shareIdOneLength, shareIdOneOffset := util.ClippedVarint64(record[n:], 1, 8192)
677		if 0 == shareIdOneOffset {
678			break unpack_switch
679		}
680		n += shareIdOneOffset
681		var shareIdOne merkle.Digest
682		err := merkle.DigestFromBytes(&shareIdOne, record[n:n+shareIdOneLength])
683		if nil != err {
684			return nil, 0, err
685		}
686		n += shareIdOneLength
687
688		// number of shares to transfer
689		quantityOne, quantityOneLength := util.FromVarint64(record[n:])
690		if 0 == quantityOneLength {
691			break unpack_switch
692		}
693		n += quantityOneLength
694
695		// owner one public key
696		ownerOneLength, ownerOneOffset := util.ClippedVarint64(record[n:], 1, 8192)
697		if 0 == ownerOneOffset {
698			break unpack_switch
699		}
700		n += ownerOneOffset
701		ownerOne, err := account.AccountFromBytes(record[n : n+ownerOneLength])
702		if nil != err {
703			return nil, 0, err
704		}
705		if ownerOne.IsTesting() != testnet {
706			return nil, 0, fault.WrongNetworkForPublicKey
707		}
708		n += ownerOneLength
709
710		// share two
711		shareIdTwoLength, shareIdTwoOffset := util.ClippedVarint64(record[n:], 1, 8192)
712		if 0 == shareIdTwoOffset {
713			break unpack_switch
714		}
715		n += shareIdTwoOffset
716		var shareIdTwo merkle.Digest
717		err = merkle.DigestFromBytes(&shareIdTwo, record[n:n+shareIdTwoLength])
718		if nil != err {
719			return nil, 0, err
720		}
721		n += shareIdTwoLength
722
723		// number of shares to transfer
724		quantityTwo, quantityTwoLength := util.FromVarint64(record[n:])
725		if 0 == quantityTwoLength {
726			break unpack_switch
727		}
728		n += quantityTwoLength
729
730		// owner two public key
731		ownerTwoLength, ownerTwoOffset := util.ClippedVarint64(record[n:], 1, 8192)
732		if 0 == ownerTwoOffset {
733			break unpack_switch
734		}
735		n += ownerTwoOffset
736		ownerTwo, err := account.AccountFromBytes(record[n : n+ownerTwoLength])
737		if nil != err {
738			return nil, 0, err
739		}
740		if ownerTwo.IsTesting() != testnet {
741			return nil, 0, fault.WrongNetworkForPublicKey
742		}
743		n += ownerTwoLength
744
745		// time limit
746		beforeBlock, beforeBlockLength := util.FromVarint64(record[n:])
747		if 0 == beforeBlockLength {
748			break unpack_switch
749		}
750		n += beforeBlockLength
751
752		// signature
753		signatureLength, signatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
754		if 0 == signatureOffset {
755			break unpack_switch
756		}
757		signature := make(account.Signature, signatureLength)
758		n += signatureOffset
759		copy(signature, record[n:n+signatureLength])
760		n += signatureLength
761
762		// countersignature
763		countersignatureLength, countersignatureOffset := util.ClippedVarint64(record[n:], 1, 8192)
764		if 0 == countersignatureOffset {
765			break unpack_switch
766		}
767		countersignature := make(account.Signature, countersignatureLength)
768		n += countersignatureOffset
769		copy(countersignature, record[n:n+countersignatureLength])
770		n += countersignatureLength
771
772		r := &ShareSwap{
773			ShareIdOne:       shareIdOne,
774			QuantityOne:      quantityOne,
775			OwnerOne:         ownerOne,
776			ShareIdTwo:       shareIdTwo,
777			QuantityTwo:      quantityTwo,
778			OwnerTwo:         ownerTwo,
779			BeforeBlock:      beforeBlock,
780			Signature:        signature,
781			Countersignature: countersignature,
782		}
783		err = r.check(testnet)
784		if nil != err {
785			return nil, 0, err
786		}
787		return r, n, nil
788
789	default: // also NullTag
790	}
791	return nil, 0, fault.NotTransactionPack
792}
793
794func unpackEscrow(record []byte, n int) (*Payment, int, error) {
795
796	// optional escrow payment
797	payment := (*Payment)(nil)
798
799	if 0 == record[n] {
800		n += 1
801	} else if 1 == record[n] {
802		n += 1
803
804		// currency
805		c, currencyLength := util.FromVarint64(record[n:])
806		if 0 == currencyLength {
807			return nil, 0, fault.NotTransactionPack
808		}
809		n += currencyLength
810		currency, err := currency.FromUint64(c)
811		if nil != err {
812			return nil, 0, err
813		}
814
815		// address
816		addressLength, addressOffset := util.ClippedVarint64(record[n:], 1, 8192)
817		if 0 == addressOffset {
818			return nil, 0, fault.NotTransactionPack
819		}
820		n += addressOffset
821		address := string(record[n : n+addressLength])
822		n += addressLength
823
824		// amount
825		amount, amountLength := util.FromVarint64(record[n:])
826		if 0 == amountLength {
827			return nil, 0, fault.NotTransactionPack
828		}
829		n += amountLength
830
831		payment = &Payment{
832			Currency: currency,
833			Address:  address,
834			Amount:   amount,
835		}
836	} else {
837		return nil, 0, fault.NotTransactionPack
838	}
839	return payment, n, nil
840}
841