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 "encoding/binary" 10 "sync" 11 12 "github.com/bitmark-inc/bitmarkd/account" 13 "github.com/bitmark-inc/bitmarkd/merkle" 14 "github.com/bitmark-inc/bitmarkd/mode" 15 "github.com/bitmark-inc/bitmarkd/storage" 16 "github.com/bitmark-inc/bitmarkd/transactionrecord" 17 "github.com/bitmark-inc/logger" 18) 19 20// to ensure synchronised ownership updates 21var toLock sync.Mutex 22 23// from storage/setup.go: 24// 25// Ownership: 26// OwnerNextCount BN - next count value to use for appending to owned items 27// OwnerList txId - list of owned items 28// OwnerTxIndex BN - position in list of owned items, for delete after transfer 29 30// Share - setup for share ownership transfer, must have a lock 31func Share( 32 trx storage.Transaction, 33 previousTxId merkle.Digest, 34 transferTxId merkle.Digest, 35 transferBlockNumber uint64, 36 currentOwner *account.Account, 37 balance uint64, 38) { 39 40 // ensure single threaded 41 toLock.Lock() 42 defer toLock.Unlock() 43 44 // delete current ownership 45 transfer(trx, previousTxId, transferTxId, transferBlockNumber, currentOwner, nil, balance) 46} 47 48// Transfer - transfer ownership 49func Transfer( 50 trx storage.Transaction, 51 previousTxId merkle.Digest, 52 transferTxId merkle.Digest, 53 transferBlockNumber uint64, 54 currentOwner *account.Account, 55 newOwner *account.Account, 56) { 57 // ensure single threaded 58 toLock.Lock() 59 defer toLock.Unlock() 60 61 transfer(trx, previousTxId, transferTxId, transferBlockNumber, currentOwner, newOwner, 0) 62} 63 64// need to hold the lock before calling this 65func transfer( 66 trx storage.Transaction, 67 previousTxId merkle.Digest, 68 transferTxId merkle.Digest, 69 transferBlockNumber uint64, 70 71 currentOwner *account.Account, 72 newOwner *account.Account, 73 quantity uint64, 74) { 75 // get count for current owner record 76 dKey := append(currentOwner.Bytes(), previousTxId[:]...) 77 dCount := trx.Get(storage.Pool.OwnerTxIndex, dKey) 78 if nil == dCount { 79 logger.Criticalf("ownership.Transfer: dKey: %x", dKey) 80 logger.Criticalf("ownership.Transfer: block number: %d", transferBlockNumber) 81 logger.Criticalf("ownership.Transfer: previous tx id: %#v", previousTxId) 82 logger.Criticalf("ownership.Transfer: transfer tx id: %#v", transferTxId) 83 logger.Criticalf("ownership.Transfer: current owner: %x %v", currentOwner.Bytes(), currentOwner) 84 if nil != newOwner { 85 logger.Criticalf("ownership.Transfer: new owner: %x %v", newOwner.Bytes(), newOwner) 86 } 87 88 // ow, err := listBitmarksFor(currentOwner, 0, 999) 89 // if nil != err { 90 // logger.Criticalf("lbf: error: %s", err) 91 // } else { 92 // logger.Criticalf("lbf: %#v", ow) 93 // } 94 95 logger.Panic("ownership.Transfer: OwnerTxIndex database corrupt") 96 } 97 98 // delete the current owners records 99 ownerData, err := GetOwnerData(trx, previousTxId, storage.Pool.OwnerData) 100 if nil != err { 101 logger.Criticalf("ownership.Transfer: invalid owner data for tx id: %s error: %s", previousTxId, err) 102 logger.Panic("ownership.Transfer: Ownership database corrupt") 103 } 104 105 oKey := append(currentOwner.Bytes(), dCount...) 106 trx.Delete(storage.Pool.OwnerList, oKey) 107 trx.Delete(storage.Pool.OwnerTxIndex, dKey) 108 109 // and the old owner data 110 trx.Delete(storage.Pool.OwnerData, previousTxId[:]) 111 112 // if no new owner only above delete was needed 113 if nil == newOwner && 0 == quantity { 114 return 115 } 116 117 switch ownerData := ownerData.(type) { 118 119 case *AssetOwnerData: 120 121 // create a share - only from an asset 122 if 0 != quantity { 123 124 // convert initial quantity to 8 byte big endian 125 quantityBytes := make([]byte, 8) 126 binary.BigEndian.PutUint64(quantityBytes, quantity) 127 128 // the ID of the share is the issue id of the bitmark 129 shareId := ownerData.issueTxId 130 131 // the total quantity of this type of share 132 shareData := append(quantityBytes, transferTxId[:]...) 133 trx.Put(storage.Pool.Shares, shareId[:], shareData, []byte{}) 134 135 // initially total quantity goes to the creator 136 fKey := append(currentOwner.Bytes(), shareId[:]...) 137 trx.Put(storage.Pool.ShareQuantity, fKey, quantityBytes, []byte{}) 138 139 // convert to share and update 140 newOwnerData := ShareOwnerData{ 141 transferBlockNumber: transferBlockNumber, 142 issueTxId: ownerData.issueTxId, 143 issueBlockNumber: ownerData.issueBlockNumber, 144 assetId: ownerData.assetId, 145 } 146 create(trx, transferTxId, newOwnerData, currentOwner) 147 return 148 } 149 150 // otherwise create new ownership record 151 ownerData.transferBlockNumber = transferBlockNumber 152 create(trx, transferTxId, ownerData, newOwner) 153 154 case *BlockOwnerData: 155 // create a share - only from an asset 156 if 0 != quantity { 157 158 // panic if not an asset (this should have been checked earlier) 159 logger.Criticalf("ownership.Transfer: ownerData for key: %x is not an asset", oKey) 160 logger.Panic("ownership.Transfer: Ownership database corrupt") 161 } 162 163 // otherwise create new ownership record 164 ownerData.transferBlockNumber = transferBlockNumber 165 create(trx, transferTxId, ownerData, newOwner) 166 167 case *ShareOwnerData: 168 169 // create a share - only from an asset 170 if 0 != quantity { 171 172 // panic if not an asset (this should have been checked earlier) 173 logger.Criticalf("ownership.Transfer: ownerData for key: %x is not an asset", oKey) 174 logger.Panic("ownership.Transfer: Ownership database corrupt") 175 } 176 177 // Note: only called on delete (block/store.go prevents share back to asset) 178 179 // convert to transfer and update 180 newOwnerData := AssetOwnerData{ 181 transferBlockNumber: transferBlockNumber, 182 issueTxId: ownerData.issueTxId, 183 issueBlockNumber: ownerData.issueBlockNumber, 184 assetId: ownerData.assetId, 185 } 186 create(trx, transferTxId, newOwnerData, currentOwner) 187 188 default: 189 // panic if not an asset (this should have been checked earlier) 190 logger.Criticalf("ownership.Transfer: unhandled owner data type: %+v", ownerData) 191 logger.Panic("ownership.Transfer: missing owner data handler") 192 } 193} 194 195// internal creation routine, must be called with lock held 196// adds items to owner's list of properties and stores the owner data 197func create( 198 trx storage.Transaction, 199 txId merkle.Digest, 200 ownerData OwnerData, 201 owner *account.Account, 202) { 203 // increment the count for owner 204 nKey := owner.Bytes() 205 count := trx.Get(storage.Pool.OwnerNextCount, nKey) 206 if nil == count { 207 count = []byte{0, 0, 0, 0, 0, 0, 0, 0} 208 } else if uint64ByteSize != len(count) { 209 logger.Panic("OwnerNextCount database corrupt") 210 } 211 newCount := make([]byte, uint64ByteSize) 212 binary.BigEndian.PutUint64(newCount, binary.BigEndian.Uint64(count)+1) 213 trx.Put(storage.Pool.OwnerNextCount, nKey, newCount, []byte{}) 214 215 // write to the owner list 216 oKey := append(owner.Bytes(), count...) 217 trx.Put(storage.Pool.OwnerList, oKey, txId[:], []byte{}) 218 219 // write new index record 220 dKey := append(owner.Bytes(), txId[:]...) 221 trx.Put(storage.Pool.OwnerTxIndex, dKey, count, []byte{}) 222 223 // save owner data record 224 trx.Put(storage.Pool.OwnerData, txId[:], ownerData.Pack(), []byte{}) 225} 226 227// CreateAsset - create the ownership record for an asset 228func CreateAsset( 229 trx storage.Transaction, 230 issueTxId merkle.Digest, 231 issueBlockNumber uint64, 232 assetId transactionrecord.AssetIdentifier, 233 newOwner *account.Account, 234) { 235 // ensure single threaded 236 toLock.Lock() 237 defer toLock.Unlock() 238 239 newData := &AssetOwnerData{ 240 transferBlockNumber: issueBlockNumber, 241 issueTxId: issueTxId, 242 issueBlockNumber: issueBlockNumber, 243 assetId: assetId, 244 } 245 246 // store to database 247 create(trx, issueTxId, newData, newOwner) 248} 249 250// CreateBlock - create the ownership record for a block 251func CreateBlock( 252 trx storage.Transaction, 253 issueTxId merkle.Digest, 254 blockNumber uint64, 255 newOwner *account.Account, 256) { 257 // ensure single threaded 258 toLock.Lock() 259 defer toLock.Unlock() 260 261 newData := &BlockOwnerData{ 262 transferBlockNumber: blockNumber, 263 issueTxId: issueTxId, 264 issueBlockNumber: blockNumber, 265 } 266 267 // store to database 268 create(trx, issueTxId, newData, newOwner) 269} 270 271// OwnerOf - find the owner of a specific transaction 272func OwnerOf(trx storage.Transaction, txId merkle.Digest) (uint64, *account.Account) { 273 var blockNumber uint64 274 var packed []byte 275 276 if nil == trx { 277 blockNumber, packed = storage.Pool.Transactions.GetNB(txId[:]) 278 } else { 279 blockNumber, packed = trx.GetNB(storage.Pool.Transactions, txId[:]) 280 } 281 282 if nil == packed { 283 return 0, nil 284 } 285 286 transaction, _, err := transactionrecord.Packed(packed).Unpack(mode.IsTesting()) 287 logger.PanicIfError("ownership.OwnerOf", err) 288 289 switch tx := transaction.(type) { 290 case *transactionrecord.BitmarkIssue: 291 return blockNumber, tx.Owner 292 293 case *transactionrecord.BitmarkTransferUnratified: 294 return blockNumber, tx.Owner 295 296 case *transactionrecord.BitmarkTransferCountersigned: 297 return blockNumber, tx.Owner 298 299 case *transactionrecord.BlockFoundation: 300 return blockNumber, tx.Owner 301 302 case *transactionrecord.BlockOwnerTransfer: 303 return blockNumber, tx.Owner 304 305 default: 306 logger.Panicf("block.OwnerOf: incorrect transaction: %v", transaction) 307 return 0, nil 308 } 309} 310 311// CurrentlyOwns - check owner currently owns this transaction id 312func CurrentlyOwns( 313 trx storage.Transaction, 314 owner *account.Account, 315 txId merkle.Digest, 316 pool storage.Handle, 317) bool { 318 dKey := append(owner.Bytes(), txId[:]...) 319 320 if nil == trx { 321 return pool.Has(dKey) 322 } 323 return trx.Has(pool, dKey) 324} 325