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 ownership 7 8import ( 9 "bytes" 10 "encoding/binary" 11 12 "github.com/bitmark-inc/bitmarkd/account" 13 "github.com/bitmark-inc/bitmarkd/merkle" 14 "github.com/bitmark-inc/bitmarkd/storage" 15 "github.com/bitmark-inc/bitmarkd/transactionrecord" 16 "github.com/bitmark-inc/logger" 17) 18 19// Record - type to represent an ownership record 20type Record struct { 21 N uint64 `json:"n,string"` 22 TxId merkle.Digest `json:"txId"` 23 IssueTxId merkle.Digest `json:"issue"` 24 Item OwnedItem `json:"item"` 25 AssetId *transactionrecord.AssetIdentifier `json:"assetId,omitempty"` 26 BlockNumber *uint64 `json:"blockNumber,omitempty"` 27} 28 29// listBitmarksFor - fetch a list of bitmarks for an owner 30func listBitmarksFor(owner *account.Account, start uint64, count int) ([]Record, error) { 31 32 startBytes := make([]byte, uint64ByteSize) 33 binary.BigEndian.PutUint64(startBytes, start) 34 35 ownerBytes := owner.Bytes() 36 prefix := append(ownerBytes, startBytes...) 37 38 cursor := storage.Pool.OwnerList.NewFetchCursor().Seek(prefix) 39 40 // owner ⧺ count → txId 41 items, err := cursor.Fetch(count) 42 if nil != err { 43 return nil, err 44 } 45 46 records := make([]Record, 0, len(items)) 47 48loop: 49 for _, item := range items { 50 n := len(item.Key) 51 split := n - uint64ByteSize 52 if split <= 0 { 53 logger.Panicf("split cannot be <= 0: %d", split) 54 } 55 itemOwner := item.Key[:n-uint64ByteSize] 56 if !bytes.Equal(ownerBytes, itemOwner) { 57 break loop 58 } 59 60 record := Record{ 61 N: binary.BigEndian.Uint64(item.Key[split:]), 62 } 63 64 merkle.DigestFromBytes(&record.TxId, item.Value) 65 66 ownerData, err := GetOwnerData(nil, record.TxId, storage.Pool.OwnerData) 67 if nil != err { 68 return nil, err 69 } 70 71 switch od := ownerData.(type) { 72 case *AssetOwnerData: 73 record.Item = OwnedAsset 74 record.IssueTxId = od.issueTxId 75 record.AssetId = &od.assetId 76 77 case *BlockOwnerData: 78 record.Item = OwnedBlock 79 record.IssueTxId = od.issueTxId 80 record.BlockNumber = &od.issueBlockNumber 81 82 case *ShareOwnerData: 83 record.Item = OwnedShare 84 record.IssueTxId = od.issueTxId 85 record.AssetId = &od.assetId 86 87 default: 88 logger.Panicf("unsupported item type: %d", item) 89 } 90 records = append(records, record) 91 } 92 93 return records, nil 94} 95