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