diff --git a/DashSync/shared/DashSync.xcdatamodeld/.xccurrentversion b/DashSync/shared/DashSync.xcdatamodeld/.xccurrentversion index 5cbe4fe8d..9697cdadc 100644 --- a/DashSync/shared/DashSync.xcdatamodeld/.xccurrentversion +++ b/DashSync/shared/DashSync.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - DashSync 20.xcdatamodel + DashSync 21.xcdatamodel diff --git a/DashSync/shared/DashSync.xcdatamodeld/DashSync 21.xcdatamodel/contents b/DashSync/shared/DashSync.xcdatamodeld/DashSync 21.xcdatamodel/contents new file mode 100644 index 000000000..e8661f27e --- /dev/null +++ b/DashSync/shared/DashSync.xcdatamodeld/DashSync 21.xcdatamodel/contents @@ -0,0 +1,529 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataClass.h b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataClass.h new file mode 100644 index 000000000..f543fb53c --- /dev/null +++ b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataClass.h @@ -0,0 +1,43 @@ +// +// Created by Vladimir Pirogov +// Copyright © 2024 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "DSSpecialTransactionEntity+CoreDataClass.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface DSAssetLockTransactionEntity : DSSpecialTransactionEntity +@end + +@interface DSAssetLockTransactionEntity (CoreDataGeneratedAccessors) + +- (void)insertObject:(DSTxOutputEntity *)value inCreditOutputsAtIndex:(NSUInteger)idx; +- (void)removeObjectFromCreditOutputsAtIndex:(NSUInteger)idx; +- (void)insertCreditOutputs:(NSArray *)value atIndexes:(NSIndexSet *)indexes; +- (void)removeCreditOutputsAtIndexes:(NSIndexSet *)indexes; +- (void)replaceObjectInCreditOutputsAtIndex:(NSUInteger)idx withObject:(DSTxOutputEntity *)value; +- (void)replaceCreditOutputsAtIndexes:(NSIndexSet *)indexes withOutputs:(NSArray *)values; +- (void)addCreditOutputsObject:(DSTxOutputEntity *)value; +- (void)removeCreditOutputsObject:(DSTxOutputEntity *)value; +- (void)addCreditOutputs:(NSOrderedSet *)values; +- (void)removeCreditOutputs:(NSOrderedSet *)values; + +@end + +NS_ASSUME_NONNULL_END + +#import "DSAssetLockTransactionEntity+CoreDataProperties.h" diff --git a/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataClass.m b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataClass.m new file mode 100644 index 000000000..6a1624362 --- /dev/null +++ b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataClass.m @@ -0,0 +1,77 @@ +// +// Created by Vladimir Pirogov +// Copyright © 2024 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "DSAddressEntity+CoreDataClass.h" +#import "DSAssetLockTransaction.h" +#import "DSAssetLockTransactionEntity+CoreDataClass.h" +#import "DSChain+Protected.h" +#import "DSChainEntity+CoreDataClass.h" +#import "DSKeyManager.h" +#import "DSTransactionFactory.h" +#import "DSTransactionOutput.h" +#import "DSTxOutputEntity+CoreDataClass.h" +#import "NSData+Dash.h" +#import "NSManagedObject+Sugar.h" +#import "NSString+Dash.h" + +@implementation DSAssetLockTransactionEntity + +- (instancetype)setAttributesFromTransaction:(DSTransaction *)transaction { + [self.managedObjectContext performBlockAndWait:^{ + [super setAttributesFromTransaction:transaction]; + DSAssetLockTransaction *tx = (DSAssetLockTransaction *)transaction; + self.specialTransactionVersion = tx.specialTransactionVersion; + NSMutableOrderedSet *creditOutputs = [self mutableOrderedSetValueForKey:@"creditOutputs"]; + while (creditOutputs.count < tx.creditOutputs.count) { + [creditOutputs addObject:[DSTxOutputEntity managedObjectInBlockedContext:self.managedObjectContext]]; + } + while (creditOutputs.count > tx.creditOutputs.count) { + + [self removeObjectFromCreditOutputsAtIndex:creditOutputs.count - 1]; + } + NSUInteger idx = 0; + for (DSTxOutputEntity *e in creditOutputs) { + [e setAttributesFromTransaction:tx outputIndex:idx++ forTransactionEntity:self]; + } + }]; + + return self; +} + +- (DSTransaction *)transactionForChain:(DSChain *)chain { + DSAssetLockTransaction *tx = (DSAssetLockTransaction *)[super transactionForChain:chain]; + tx.type = DSTransactionType_AssetLock; + [self.managedObjectContext performBlockAndWait:^{ + tx.specialTransactionVersion = self.specialTransactionVersion; + for (DSTxOutputEntity *e in self.creditOutputs) { + NSString *address = e.address; + if (!address && e.script) { + address = [DSKeyManager addressWithScriptPubKey:e.script forChain:tx.chain]; + } + DSTransactionOutput *transactionOutput = [DSTransactionOutput transactionOutputWithAmount:e.value address:address outScript:e.script onChain:tx.chain]; + [tx.creditOutputs addObject:transactionOutput]; + } + }]; + + return tx; +} + +- (Class)transactionClass { + return [DSAssetLockTransactionEntity class]; +} + +@end diff --git a/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataProperties.h b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataProperties.h new file mode 100644 index 000000000..fafef85b5 --- /dev/null +++ b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataProperties.h @@ -0,0 +1,31 @@ +// +// Created by Vladimir Pirogov +// Copyright © 2024 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "DSAssetLockTransactionEntity+CoreDataClass.h" + + +NS_ASSUME_NONNULL_BEGIN + +@interface DSAssetLockTransactionEntity (CoreDataProperties) + ++ (NSFetchRequest *)fetchRequest; + +@property (nonatomic, retain) NSOrderedSet *creditOutputs; + +@end + +NS_ASSUME_NONNULL_END diff --git a/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataProperties.m b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataProperties.m new file mode 100644 index 000000000..3b8e838d9 --- /dev/null +++ b/DashSync/shared/Models/Entities/DSAssetLockTransactionEntity+CoreDataProperties.m @@ -0,0 +1,28 @@ +// +// Created by Vladimir Pirogov +// Copyright © 2024 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "DSAssetLockTransactionEntity+CoreDataProperties.h" + +@implementation DSAssetLockTransactionEntity (CoreDataProperties) + ++ (NSFetchRequest *)fetchRequest { + return [NSFetchRequest fetchRequestWithEntityName:@"DSAssetLockTransactionEntity"]; +} + +@dynamic creditOutputs; + +@end diff --git a/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataClass.h b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataClass.h new file mode 100644 index 000000000..da8899d08 --- /dev/null +++ b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataClass.h @@ -0,0 +1,29 @@ +// +// Created by Vladimir Pirogov +// Copyright © 2024 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "DSSpecialTransactionEntity+CoreDataClass.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface DSAssetUnlockTransactionEntity : DSSpecialTransactionEntity + +@end + +NS_ASSUME_NONNULL_END + +#import "DSAssetUnlockTransactionEntity+CoreDataProperties.h" diff --git a/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataClass.m b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataClass.m new file mode 100644 index 000000000..aa67b7306 --- /dev/null +++ b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataClass.m @@ -0,0 +1,64 @@ +// +// Created by Vladimir Pirogov +// Copyright © 2024 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "DSAddressEntity+CoreDataClass.h" +#import "DSAssetUnlockTransaction.h" +#import "DSAssetUnlockTransactionEntity+CoreDataClass.h" +#import "DSChain+Protected.h" +#import "DSChainEntity+CoreDataClass.h" +#import "DSTransaction.h" +#import "DSTransactionFactory.h" +#import "NSData+Dash.h" +#import "NSManagedObject+Sugar.h" + +@implementation DSAssetUnlockTransactionEntity + +- (instancetype)setAttributesFromTransaction:(DSTransaction *)transaction { + [self.managedObjectContext performBlockAndWait:^{ + [super setAttributesFromTransaction:transaction]; + DSAssetUnlockTransaction *tx = (DSAssetUnlockTransaction *)transaction; + self.specialTransactionVersion = tx.specialTransactionVersion; + self.index = tx.index; + self.fee = tx.fee; + self.requestedHeight = tx.requestedHeight; + self.quorumHash = uint256_data(tx.quorumHash); + self.quorumSignature = uint768_data(tx.quorumSignature); + }]; + + return self; +} + +- (DSTransaction *)transactionForChain:(DSChain *)chain { + DSAssetUnlockTransaction *tx = (DSAssetUnlockTransaction *)[super transactionForChain:chain]; + tx.type = DSTransactionType_AssetUnlock; + [self.managedObjectContext performBlockAndWait:^{ + tx.specialTransactionVersion = self.specialTransactionVersion; + tx.index = self.index; + tx.fee = self.fee; + tx.requestedHeight = self.requestedHeight; + tx.quorumHash = self.quorumHash.UInt256; + tx.quorumSignature = self.quorumSignature.UInt768; + }]; + + return tx; +} + +- (Class)transactionClass { + return [DSAssetUnlockTransaction class]; +} + +@end diff --git a/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataProperties.h b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataProperties.h new file mode 100644 index 000000000..9c2a7baa8 --- /dev/null +++ b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataProperties.h @@ -0,0 +1,35 @@ +// +// Created by Vladimir Pirogov +// Copyright © 2024 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "DSAssetUnlockTransactionEntity+CoreDataClass.h" + + +NS_ASSUME_NONNULL_BEGIN + +@interface DSAssetUnlockTransactionEntity (CoreDataProperties) + ++ (NSFetchRequest *)fetchRequest; + +@property (nonatomic, assign) uint64_t index; +@property (nonatomic, assign) uint32_t fee; +@property (nonatomic, assign) uint32_t requestedHeight; +@property (nullable, nonatomic, retain) NSData *quorumHash; +@property (nullable, nonatomic, retain) NSData *quorumSignature; + +@end + +NS_ASSUME_NONNULL_END diff --git a/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataProperties.m b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataProperties.m new file mode 100644 index 000000000..b5d9b60d6 --- /dev/null +++ b/DashSync/shared/Models/Entities/DSAssetUnlockTransactionEntity+CoreDataProperties.m @@ -0,0 +1,32 @@ +// +// Created by Vladimir Pirogov +// Copyright © 2024 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "DSAssetUnlockTransactionEntity+CoreDataProperties.h" + +@implementation DSAssetUnlockTransactionEntity (CoreDataProperties) + ++ (NSFetchRequest *)fetchRequest { + return [NSFetchRequest fetchRequestWithEntityName:@"DSAssetUnlockTransactionEntity"]; +} + +@dynamic index; +@dynamic fee; +@dynamic requestedHeight; +@dynamic quorumHash; +@dynamic quorumSignature; + +@end diff --git a/DashSync/shared/Models/Masternode/DSMasternodeListService.m b/DashSync/shared/Models/Masternode/DSMasternodeListService.m index 3c8c15700..17c7dd746 100644 --- a/DashSync/shared/Models/Masternode/DSMasternodeListService.m +++ b/DashSync/shared/Models/Masternode/DSMasternodeListService.m @@ -261,7 +261,7 @@ - (void)removeFromRetrievalQueue:(NSData *)masternodeBlockHashData { double count = self.retrievalQueue.count; @synchronized (self.chain.chainManager.syncState) { self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueCount = count; - self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueMaxAmount = self.retrievalQueueMaxAmount; + self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueMaxAmount = (uint32_t) self.retrievalQueueMaxAmount; DSLog(@"[%@] Masternode list queue updated: %f/%lu", self.chain.name, count, self.retrievalQueueMaxAmount); [self.chain.chainManager notifySyncStateChanged]; } @@ -275,7 +275,7 @@ - (void)cleanListsRetrievalQueue { [self.retrievalQueue removeAllObjects]; @synchronized (self.chain.chainManager.syncState) { self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueCount = 0; - self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueMaxAmount = self.retrievalQueueMaxAmount; + self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueMaxAmount = (uint32_t) self.retrievalQueueMaxAmount; DSLog(@"[%@] Masternode list queue cleaned up: 0/%lu", self.chain.name, self.retrievalQueueMaxAmount); [self.chain.chainManager notifySyncStateChanged]; } @@ -302,8 +302,8 @@ - (void)updateMasternodeRetrievalQueue { return [self.store heightForBlockHash:obj1.UInt256] < [self.store heightForBlockHash:obj2.UInt256] ? NSOrderedAscending : NSOrderedDescending; }]; @synchronized (self.chain.chainManager.syncState) { - self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueCount = currentCount; - self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueMaxAmount = self.retrievalQueueMaxAmount; + self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueCount = (uint32_t) currentCount; + self.chain.chainManager.syncState.masternodeListSyncInfo.retrievalQueueMaxAmount = (uint32_t) self.retrievalQueueMaxAmount; DSLog(@"[%@] Masternode list queue updated: %lu/%lu", self.chain.name, currentCount, self.retrievalQueueMaxAmount); [self.chain.chainManager notifySyncStateChanged]; } diff --git a/DashSync/shared/Models/Notifications/DSSyncState.m b/DashSync/shared/Models/Notifications/DSSyncState.m index 8b5481480..09f03a4f7 100644 --- a/DashSync/shared/Models/Notifications/DSSyncState.m +++ b/DashSync/shared/Models/Notifications/DSSyncState.m @@ -28,7 +28,7 @@ - (id)copyWithZone:(NSZone *)zone { return copy; } - (NSString *)description { - return [NSString stringWithFormat:@"%u/%u/%u/%u", + return [NSString stringWithFormat:@"%u/%u/%f/%u", self.retrievalQueueCount, self.retrievalQueueMaxAmount, self.storedCount, diff --git a/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.h b/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.h index 066472548..ac5cb6549 100644 --- a/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.h +++ b/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.h @@ -41,6 +41,7 @@ typedef NS_ENUM(NSInteger, DSCoreDataMigrationVersionValue) DSCoreDataMigrationVersionValue_18 = 18, DSCoreDataMigrationVersionValue_19 = 19, DSCoreDataMigrationVersionValue_20 = 20, + DSCoreDataMigrationVersionValue_21 = 21, }; @interface DSCoreDataMigrationVersion : NSObject diff --git a/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.m b/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.m index 5703cf186..e6526f1f1 100644 --- a/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.m +++ b/DashSync/shared/Models/Persistence/Migration/Internal/DSCoreDataMigrationVersion.m @@ -20,7 +20,7 @@ @implementation DSCoreDataMigrationVersion + (DSCoreDataMigrationVersionValue)current { - return DSCoreDataMigrationVersionValue_20; + return DSCoreDataMigrationVersionValue_21; } + (NSString *)modelResourceForVersion:(DSCoreDataMigrationVersionValue)version { @@ -45,6 +45,7 @@ + (NSString *)modelResourceForVersion:(DSCoreDataMigrationVersionValue)version { case DSCoreDataMigrationVersionValue_18: return @"DashSync 18"; case DSCoreDataMigrationVersionValue_19: return @"DashSync 19"; case DSCoreDataMigrationVersionValue_20: return @"DashSync 20"; + case DSCoreDataMigrationVersionValue_21: return @"DashSync 21"; default: return [NSString stringWithFormat:@"DashSync %ld", (long)version]; } diff --git a/DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.h b/DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.h new file mode 100644 index 000000000..01349ba38 --- /dev/null +++ b/DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.h @@ -0,0 +1,31 @@ +// +// Created by Vladimir Pirogov +// Copyright © 2024 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "DSTransaction.h" +#import "DSTransactionOutput.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface DSAssetLockTransaction : DSTransaction + +@property (nonatomic, assign) uint8_t specialTransactionVersion; +@property (nonatomic, assign) NSMutableArray *creditOutputs; + +@end + +NS_ASSUME_NONNULL_END diff --git a/DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.m b/DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.m new file mode 100644 index 000000000..1ce845e2a --- /dev/null +++ b/DashSync/shared/Models/Transactions/Base/DSAssetLockTransaction.m @@ -0,0 +1,61 @@ +// +// Created by Vladimir Pirogov +// Copyright © 2024 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "DSAssetLockTransaction.h" +#import "DSChain.h" +#import "DSTransactionFactory.h" +#import "NSData+Dash.h" + +@implementation DSAssetLockTransaction + +- (instancetype)initWithMessage:(NSData *)message onChain:(DSChain *)chain { + if (!(self = [super initWithMessage:message onChain:chain])) + return nil; + self.type = DSTransactionType_AssetLock; + NSUInteger length = message.length; + uint32_t off = self.payloadOffset; + + if (length - off < 1) return nil; + NSNumber *payloadLengthSize = nil; + __unused uint64_t payloadLength = [message varIntAtOffset:off length:&payloadLengthSize]; + off += payloadLengthSize.unsignedLongValue; + + if (length - off < 1) return nil; + self.specialTransactionVersion = [message UInt8AtOffset:off]; + off += 1; + + NSNumber *l = 0; + if (length - off < 1) return nil; + uint64_t count = (NSUInteger)[message varIntAtOffset:off length:&l]; // output count + off += l.unsignedIntegerValue; + + NSMutableArray *creditOutputs = [NSMutableArray arrayWithCapacity:count]; + for (NSUInteger i = 0; i < count; i++) { // outputs + uint64_t amount = [message UInt64AtOffset:off]; // output amount + off += sizeof(uint64_t); + NSData *outScript = [message dataAtOffset:off length:&l]; // output script + off += l.unsignedIntegerValue; + DSTransactionOutput *transactionOutput = [DSTransactionOutput transactionOutputWithAmount:amount outScript:outScript onChain:self.chain]; + [creditOutputs addObject:transactionOutput]; + } + self.creditOutputs = creditOutputs; + self.payloadOffset = off; + self.txHash = self.data.SHA256_2; + + return self; +} +@end diff --git a/DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.h b/DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.h new file mode 100644 index 000000000..2a825a4de --- /dev/null +++ b/DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.h @@ -0,0 +1,34 @@ +// +// Created by Vladimir Pirogov +// Copyright © 2024 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "BigIntTypes.h" +#import "DSTransaction.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface DSAssetUnlockTransaction : DSTransaction +@property (nonatomic, assign) uint8_t specialTransactionVersion; +@property (nonatomic, assign) uint64_t index; +@property (nonatomic, assign) uint32_t fee; +@property (nonatomic, assign) uint32_t requestedHeight; +@property (nonatomic, assign) UInt256 quorumHash; +@property (nonatomic, assign) UInt768 quorumSignature; + +@end + +NS_ASSUME_NONNULL_END diff --git a/DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.m b/DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.m new file mode 100644 index 000000000..01824db34 --- /dev/null +++ b/DashSync/shared/Models/Transactions/Base/DSAssetUnlockTransaction.m @@ -0,0 +1,95 @@ +// +// Created by Vladimir Pirogov +// Copyright © 2024 Dash Core Group. All rights reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "DSAssetUnlockTransaction.h" +#import "DSChain.h" +#import "DSTransactionFactory.h" +#import "NSData+Dash.h" +#import "NSMutableData+Dash.h" + +@implementation DSAssetUnlockTransaction + +- (instancetype)initWithMessage:(NSData *)message onChain:(DSChain *)chain { + if (!(self = [super initWithMessage:message onChain:chain])) + return nil; + self.type = DSTransactionType_AssetUnlock; + NSUInteger length = message.length; + uint32_t off = self.payloadOffset; + + if (length - off < 1) return nil; + NSNumber *payloadLengthSize = nil; + uint64_t payloadLength = [message varIntAtOffset:off length:&payloadLengthSize]; + off += payloadLengthSize.unsignedLongValue; + + if (length - off < 1) return nil; + self.specialTransactionVersion = [message UInt8AtOffset:off]; + off += 1; + if (length - off < 8) return nil; + self.index = [message UInt64AtOffset:off]; + off += 8; + if (length - off < 4) return nil; + self.fee = [message UInt32AtOffset:off]; + off += 4; + if (length - off < 4) return nil; + self.requestedHeight = [message UInt32AtOffset:off]; + off += 4; + + if (length - off < 32) return nil; + self.quorumHash = [message UInt256AtOffset:off]; + off += 32; + if (length - off < 96) return nil; + self.quorumSignature = [message UInt768AtOffset:off]; + off += 96; + + self.payloadOffset = off; + if ([self payloadData].length != payloadLength) return nil; + self.txHash = self.data.SHA256_2; + + return self; + +} +- (BOOL)transactionTypeRequiresInputs { + return NO; +} +- (NSData *)payloadData { + return [self basePayloadData]; +} + +- (NSData *)basePayloadData { + NSMutableData *data = [NSMutableData data]; + [data appendUInt8:self.specialTransactionVersion]; + [data appendUInt64:self.index]; + [data appendUInt32:self.fee]; + [data appendUInt32:self.requestedHeight]; + [data appendUInt256:self.quorumHash]; + [data appendUInt768:self.quorumSignature]; + return data; +} + +- (NSData *)toDataWithSubscriptIndex:(NSUInteger)subscriptIndex { + @synchronized(self) { + NSMutableData *data = [[super toDataWithSubscriptIndex:subscriptIndex] mutableCopy]; + [data appendCountedData:[self payloadData]]; + if (subscriptIndex != NSNotFound) [data appendUInt32:SIGHASH_ALL]; + return data; + } +} +- (size_t)size { + return [super size] + [self payloadData].length; +} + +@end diff --git a/DashSync/shared/Models/Transactions/Base/DSTransaction.m b/DashSync/shared/Models/Transactions/Base/DSTransaction.m index f6f0e1f9f..428853fb9 100644 --- a/DashSync/shared/Models/Transactions/Base/DSTransaction.m +++ b/DashSync/shared/Models/Transactions/Base/DSTransaction.m @@ -28,6 +28,7 @@ #import "DSAccount.h" #import "DSAddressEntity+CoreDataClass.h" +#import "DSAssetUnlockTransaction.h" #import "DSChain.h" #import "DSChainEntity+CoreDataClass.h" #import "DSChainManager.h" @@ -408,7 +409,7 @@ - (NSData *)toDataWithSubscriptIndex:(NSUInteger)subscriptIndex { NSArray *outputs = self.outputs; NSUInteger inputsCount = inputs.count; NSUInteger outputsCount = outputs.count; - BOOL forSigHash = ([self isMemberOfClass:[DSTransaction class]] || [self isMemberOfClass:[DSCreditFundingTransaction class]]) && subscriptIndex != NSNotFound; + BOOL forSigHash = ([self isMemberOfClass:[DSTransaction class]] || [self isMemberOfClass:[DSCreditFundingTransaction class]] || [self isMemberOfClass:[DSAssetUnlockTransaction class]]) && subscriptIndex != NSNotFound; NSUInteger dataSize = 8 + [NSMutableData sizeOfVarInt:inputsCount] + [NSMutableData sizeOfVarInt:outputsCount] + TX_INPUT_SIZE * inputsCount + TX_OUTPUT_SIZE * outputsCount + (forSigHash ? 4 : 0); NSMutableData *d = [NSMutableData dataWithCapacity:dataSize]; diff --git a/DashSync/shared/Models/Transactions/DSTransactionFactory.h b/DashSync/shared/Models/Transactions/DSTransactionFactory.h index a31f8c34d..6f2e876a8 100644 --- a/DashSync/shared/Models/Transactions/DSTransactionFactory.h +++ b/DashSync/shared/Models/Transactions/DSTransactionFactory.h @@ -20,8 +20,8 @@ typedef NS_ENUM(NSUInteger, DSTransactionType) DSTransactionType_ProviderUpdateRevocation = 4, DSTransactionType_Coinbase = 5, DSTransactionType_QuorumCommitment = 6, - DSTransactionType_SubscriptionRegistration = 8, - DSTransactionType_SubscriptionTopUp = 9, + DSTransactionType_AssetLock = 8, + DSTransactionType_AssetUnlock = 9, DSTransactionType_SubscriptionResetKey = 10, DSTransactionType_SubscriptionCloseAccount = 11, DSTransactionType_Transition = 12, diff --git a/DashSync/shared/Models/Transactions/DSTransactionFactory.m b/DashSync/shared/Models/Transactions/DSTransactionFactory.m index e47c7d11a..4bc66e4d9 100644 --- a/DashSync/shared/Models/Transactions/DSTransactionFactory.m +++ b/DashSync/shared/Models/Transactions/DSTransactionFactory.m @@ -5,6 +5,8 @@ // Created by Sam Westrich on 7/12/18. // +#import "DSAssetLockTransaction.h" +#import "DSAssetUnlockTransaction.h" #import "DSTransactionFactory.h" #import "DSBlockchainIdentityCloseTransition.h" #import "DSBlockchainIdentityRegistrationTransition.h" @@ -56,6 +58,10 @@ + (DSTransaction *)transactionWithMessage:(NSData *)message onChain:(DSChain *)c return [DSProviderUpdateRegistrarTransaction transactionWithMessage:message onChain:chain]; case DSTransactionType_ProviderUpdateRevocation: return [DSProviderUpdateRevocationTransaction transactionWithMessage:message onChain:chain]; + case DSTransactionType_AssetLock: + return [DSAssetLockTransaction transactionWithMessage:message onChain:chain]; + case DSTransactionType_AssetUnlock: + return [DSAssetUnlockTransaction transactionWithMessage:message onChain:chain]; case DSTransactionType_QuorumCommitment: return [DSQuorumCommitmentTransaction transactionWithMessage:message onChain:chain]; default: @@ -69,9 +75,9 @@ + (BOOL)ignoreMessagesOfTransactionType:(DSTransactionType)transactionType { return FALSE; case DSTransactionType_Coinbase: return FALSE; - case DSTransactionType_SubscriptionRegistration: + case DSTransactionType_AssetLock: return FALSE; - case DSTransactionType_SubscriptionTopUp: + case DSTransactionType_AssetUnlock: return FALSE; case DSTransactionType_SubscriptionCloseAccount: return FALSE; diff --git a/DashSync/shared/Models/Wallet/DSSpecialTransactionsWalletHolder.m b/DashSync/shared/Models/Wallet/DSSpecialTransactionsWalletHolder.m index 60509ae7d..ba087139c 100644 --- a/DashSync/shared/Models/Wallet/DSSpecialTransactionsWalletHolder.m +++ b/DashSync/shared/Models/Wallet/DSSpecialTransactionsWalletHolder.m @@ -5,6 +5,8 @@ // Created by Sam Westrich on 3/5/19. // +#import "DSAssetLockTransaction.h" +#import "DSAssetUnlockTransaction.h" #import "DSSpecialTransactionsWalletHolder.h" #import "DSAddressEntity+CoreDataClass.h" #import "DSChain.h" @@ -37,6 +39,8 @@ @interface DSSpecialTransactionsWalletHolder () @property (nonatomic, strong) NSMutableDictionary *providerUpdateRegistrarTransactions; @property (nonatomic, strong) NSMutableDictionary *providerUpdateRevocationTransactions; @property (nonatomic, strong) NSMutableDictionary *creditFundingTransactions; +@property (nonatomic, strong) NSMutableDictionary *assetLockTransactions; +@property (nonatomic, strong) NSMutableDictionary *assetUnlockTransactions; @property (nonatomic, strong) NSMutableArray *transactionsToSave; @property (nonatomic, strong) NSMutableDictionary *> *transactionsToSaveInBlockSave; @@ -154,6 +158,18 @@ - (BOOL)registerTransaction:(DSTransaction *)transaction saveImmediately:(BOOL)s [self.creditFundingTransactions setObject:transaction forKey:uint256_data(creditFundingTransaction.creditBurnIdentityIdentifier)]; added = TRUE; } + } else if ([transaction isMemberOfClass:[DSAssetLockTransaction class]]) { + DSAssetLockTransaction *assetLockTransaction = (DSAssetLockTransaction *)transaction; + if (![self.assetLockTransactions objectForKey:uint256_data(assetLockTransaction.txHash)]) { + [self.assetLockTransactions setObject:transaction forKey:uint256_data(assetLockTransaction.txHash)]; + added = TRUE; + } + } else if ([transaction isMemberOfClass:[DSAssetUnlockTransaction class]]) { + DSAssetUnlockTransaction *assetUnlockTransaction = (DSAssetUnlockTransaction *)transaction; + if (![self.assetUnlockTransactions objectForKey:uint256_data(assetUnlockTransaction.txHash)]) { + [self.assetUnlockTransactions setObject:transaction forKey:uint256_data(assetUnlockTransaction.txHash)]; + added = TRUE; + } } else { NSAssert(FALSE, @"unknown transaction type being registered"); return NO; @@ -198,6 +214,12 @@ - (void)loadTransactions { } else if ([transaction isMemberOfClass:[DSCreditFundingTransaction class]]) { DSCreditFundingTransaction *creditFundingTransaction = (DSCreditFundingTransaction *)transaction; [self.creditFundingTransactions setObject:transaction forKey:uint256_data(creditFundingTransaction.creditBurnIdentityIdentifier)]; + } else if ([transaction isMemberOfClass:[DSAssetLockTransaction class]]) { + DSAssetLockTransaction *assetLockTransaction = (DSAssetLockTransaction *)transaction; + [self.assetLockTransactions setObject:transaction forKey:uint256_data(assetLockTransaction.txHash)]; + } else if ([transaction isMemberOfClass:[DSAssetUnlockTransaction class]]) { + DSAssetUnlockTransaction *assetUnlockTransaction = (DSAssetUnlockTransaction *)transaction; + [self.assetUnlockTransactions setObject:transaction forKey:uint256_data(assetUnlockTransaction.txHash)]; } else { //the other ones don't have addresses in payload NSAssert(FALSE, @"Unknown special transaction type"); } diff --git a/Example/DashSync/DSTransactionDetailViewController.m b/Example/DashSync/DSTransactionDetailViewController.m index 8ba0bbde3..ed4552701 100644 --- a/Example/DashSync/DSTransactionDetailViewController.m +++ b/Example/DashSync/DSTransactionDetailViewController.m @@ -6,6 +6,8 @@ // Copyright © 2018 Dash Core Group. All rights reserved. // +#import "DSAssetLockTransaction.h" +#import "DSAssetUnlockTransaction.h" #import "DSTransactionDetailViewController.h" #import "BRCopyLabel.h" #import "DSTransactionAmountTableViewCell.h" @@ -286,6 +288,10 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell.statusLabel.text = @"Coinbase Transaction"; } else if ([self.transaction isMemberOfClass:[DSCreditFundingTransaction class]]) { cell.statusLabel.text = @"Classical Credit Funding Transaction"; + } else if ([self.transaction isMemberOfClass:[DSAssetLockTransaction class]]) { + cell.statusLabel.text = @"Asset Lock Transaction"; + } else if ([self.transaction isMemberOfClass:[DSAssetUnlockTransaction class]]) { + cell.statusLabel.text = @"Asset Unlock Transaction"; } else { cell.statusLabel.text = @"Classical Transaction"; } diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 0dd922b4b..27ed1c626 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -657,7 +657,7 @@ PODS: - gRPC/Interface-Legacy (1.49.0): - gRPC-RxLibrary/Interface (= 1.49.0) - KVO-MVVM (0.5.1) - - Protobuf (3.28.2) + - Protobuf (3.28.3) - SDWebImage (5.14.3): - SDWebImage/Core (= 5.14.3) - SDWebImage/Core (5.14.3) @@ -727,7 +727,7 @@ SPEC CHECKSUMS: gRPC-ProtoRPC: 1c223e0f1732bb8d0b9e9e0ea60cc0fe995b8e2d gRPC-RxLibrary: 92327f150e11cf3b1c0f52e083944fd9f5cb5d1e KVO-MVVM: 4df3afd1f7ebcb69735458b85db59c4271ada7c6 - Protobuf: 28c89b24435762f60244e691544ed80f50d82701 + Protobuf: 5a8a7781d8e1004302f108977ac2d5b99323146f SDWebImage: 9c36e66c8ce4620b41a7407698dda44211a96764 tinycbor: d4d71dddda1f8392fbb4249f63faf8552f327590 TinyCborObjc: 5204540fb90ff0c40fb22d408fa51bab79d78a80 diff --git a/Example/Tests/DSTransactionTests.m b/Example/Tests/DSTransactionTests.m index 7ae28a403..200cf6dc3 100644 --- a/Example/Tests/DSTransactionTests.m +++ b/Example/Tests/DSTransactionTests.m @@ -8,6 +8,7 @@ #import +#import "DSAssetUnlockTransaction.h" #import "DSAuthenticationKeysDerivationPath.h" #import "DSBlockchainIdentityCloseTransition.h" #import "DSBlockchainIdentityRegistrationTransition.h" @@ -91,6 +92,11 @@ - (void)testTransaction { XCTAssertEqualObjects(d, tx.data, @"[DSTransaction transactionWithMessage:]"); processor_destroy_opaque_key(k); } +- (void)testAssetUnlockTx { + NSData *transactionData = @"030009000001a02ffa0d000000001976a9146641c13e0ee2ce2cdf70852bb7ae9853c01f29a988ac0000000091014e00000000000000be000000273e11004130304f40d1820b5e239baecd35249263b1206a1c76e66053ec39a04501000093d3851b6bda0518da51ff8932ef3570be20e7978369dd312947326e135004915c10b5fe0e31e572c40f41cdd941bed8115e314573faf472e1065ca370bdff486db8eaa6bbcba3943e6e5ada6a3c30dee70e39811814e59e1ffc54f3c9fca04f".hexToData; + DSAssetUnlockTransaction *tx = [[DSAssetUnlockTransaction alloc] initWithMessage:transactionData onChain:[DSChain testnet]]; + XCTAssert(tx, @"Bad Asset Unlock Tx"); +} - (void)testBlockchainIdentityFundingTransactionUniqueId { NSData *transactionData = @"0300000002b74030bbda6edd804d4bfb2bdbbb7c207a122f3af2f6283de17074a42c6a5417020000006b483045022100815b175ab1a8fde7d651d78541ba73d2e9b297e6190f5244e1957004aa89d3c902207e1b164499569c1f282fe5533154495186484f7db22dc3dc1ccbdc9b47d997250121027f69794d6c4c942392b1416566aef9eaade43fbf07b63323c721b4518127baadffffffffb74030bbda6edd804d4bfb2bdbbb7c207a122f3af2f6283de17074a42c6a5417010000006b483045022100a7c94fe1bb6ffb66d2bb90fd8786f5bd7a0177b0f3af20342523e64291f51b3e02201f0308f1034c0f6024e368ca18949be42a896dda434520fa95b5651dc5ad3072012102009e3f2eb633ee12c0143f009bf773155a6c1d0f14271d30809b1dc06766aff0ffffffff031027000000000000166a1414ec6c36e6c39a9181f3a261a08a5171425ac5e210270000000000001976a91414ec6c36e6c39a9181f3a261a08a5171425ac5e288acc443953b000000001976a9140d1775b9ed85abeb19fd4a7d8cc88b08a29fe6de88ac00000000".hexToData;