diff --git a/BRWalletManager.c b/BRWalletManager.c index ccfb57f84..4d7a39e53 100644 --- a/BRWalletManager.c +++ b/BRWalletManager.c @@ -155,7 +155,10 @@ fileServiceTypeTransactionV1Reader (BRFileServiceContext context, static BRArrayOf(BRTransaction*) initialTransactionsLoad (BRWalletManager manager) { BRSetOf(BRTransaction*) transactionSet = BRSetNew(BRTransactionHash, BRTransactionEq, 100); - fileServiceLoad (manager->fileService, transactionSet, fileServiceTypeTransactions, 1); + if (1 != fileServiceLoad (manager->fileService, transactionSet, fileServiceTypeTransactions, 1)) { + BRSetFree(transactionSet); + return NULL; + } size_t transactionsCount = BRSetCount(transactionSet); @@ -235,7 +238,10 @@ fileServiceTypeBlockV1Reader (BRFileServiceContext context, static BRArrayOf(BRMerkleBlock*) initialBlocksLoad (BRWalletManager manager) { BRSetOf(BRTransaction*) blockSet = BRSetNew(BRMerkleBlockHash, BRMerkleBlockEq, 100); - fileServiceLoad (manager->fileService, blockSet, fileServiceTypeBlocks, 1); + if (1 != fileServiceLoad (manager->fileService, blockSet, fileServiceTypeBlocks, 1)) { + BRSetFree (blockSet); + return NULL; + } size_t blocksCount = BRSetCount(blockSet); @@ -301,7 +307,10 @@ static BRArrayOf(BRPeer) initialPeersLoad (BRWalletManager manager) { /// Load peers for the wallet manager. BRSetOf(BRPeer*) peerSet = BRSetNew(BRPeerHash, BRPeerEq, 100); - fileServiceLoad (manager->fileService, peerSet, fileServiceTypePeers, 1); + if (1 != fileServiceLoad (manager->fileService, peerSet, fileServiceTypePeers, 1)) { + BRSetFree(peerSet); + return NULL; + } size_t peersCount = BRSetCount(peerSet); BRPeer *peersRefs[peersCount]; @@ -319,6 +328,32 @@ initialPeersLoad (BRWalletManager manager) { return peers; } +static void +bwmFileServiceErrorHandler (BRFileServiceContext context, + BRFileService fs, + BRFileServiceError error) { + BRWalletManager bwm = (BRWalletManager) context; + + switch (error.type) { + case FILE_SERVICE_IMPL: + // This actually a FATAL - an unresolvable coding error. + _peer_log ("bread: FileService Error: IMPL: %s", error.u.impl.reason); + break; + case FILE_SERVICE_UNIX: + _peer_log ("bread: FileService Error: UNIX: %s", strerror(error.u.unix.error)); + break; + case FILE_SERVICE_ENTITY: + // This is likely a coding error too. + _peer_log ("bread: FileService Error: ENTITY (%s); %s", + error.u.entity.type, + error.u.entity.reason); + break; + } + _peer_log ("bread: FileService Error: FORCED SYNC%s", ""); + + if (NULL != bwm->peerManager) + BRPeerManagerRescan (bwm->peerManager); +} /// /// MARK: Wallet Manager /// @@ -341,7 +376,9 @@ BRWalletManagerNew (BRWalletManagerClient client, // // Create the File Service w/ associated types. // - manager->fileService = fileServiceCreate (baseStoragePath, networkName, currencyName); + manager->fileService = fileServiceCreate (baseStoragePath, networkName, currencyName, + manager, + bwmFileServiceErrorHandler); if (NULL == manager->fileService) { free (manager); return NULL; } /// Transaction @@ -376,6 +413,22 @@ BRWalletManagerNew (BRWalletManagerClient client, /// Load transactions for the wallet manager. BRArrayOf(BRTransaction*) transactions = initialTransactionsLoad(manager); + /// Load blocks and peers for the peer manager. + BRArrayOf(BRMerkleBlock*) blocks = initialBlocksLoad(manager); + BRArrayOf(BRPeer) peers = initialPeersLoad(manager); + + // If any of these are NULL, then there was a failure; on a failure they all need to be cleared + // which will cause a *FULL SYNC* + if (NULL == transactions || NULL == blocks || NULL == peers) { + if (NULL == transactions) array_new (transactions, 1); + else array_clear(transactions); + + if (NULL == blocks) array_new (blocks, 1); + else array_clear(blocks); + + if (NULL == peers) array_new (peers, 1); + else array_clear(peers); + } manager->wallet = BRWalletNew (transactions, array_count(transactions), mpk, fork); BRWalletSetCallbacks (manager->wallet, manager, @@ -384,7 +437,6 @@ BRWalletManagerNew (BRWalletManagerClient client, _BRWalletManagerTxUpdated, _BRWalletManagerTxDeleted); - array_free(transactions); client.funcWalletEvent (manager, manager->wallet, @@ -392,10 +444,6 @@ BRWalletManagerNew (BRWalletManagerClient client, BITCOIN_WALLET_CREATED }); - /// Load blocks and peers for the peer manager. - BRArrayOf(BRMerkleBlock*) blocks = initialBlocksLoad(manager); - BRArrayOf(BRPeer) peers = initialPeersLoad(manager); - manager->peerManager = BRPeerManagerNew (params, manager->wallet, earliestKeyTime, blocks, array_count(blocks), peers, array_count(peers)); @@ -409,7 +457,7 @@ BRWalletManagerNew (BRWalletManagerClient client, _BRWalletManagerNetworkIsReachabele, _BRWalletManagerThreadCleanup); - array_free(blocks); array_free(peers); + array_free(transactions); array_free(blocks); array_free(peers); return manager; } diff --git a/Swift/BRCrypto/BRBitcoin.swift b/Swift/BRCrypto/BRBitcoin.swift index f232e8cea..f75dd5a25 100644 --- a/Swift/BRCrypto/BRBitcoin.swift +++ b/Swift/BRCrypto/BRBitcoin.swift @@ -265,7 +265,7 @@ public class BitcoinWallet: Wallet { /// BRCorePeerManager. /// public class BitcoinWalletManager: WalletManager { - #if false + #if true internal let coreWalletManager: BRCoreWalletManager #endif @@ -379,7 +379,7 @@ public class BitcoinWalletManager: WalletManager { self.mode = mode self.state = WalletManagerState.created -#if false +#if true let client = BRWalletManagerClient ( funcTransactionEvent: { (this, coreWallet, coreTransaction, event) in if let bwm = BitcoinWalletManager.lookup (manager: this), @@ -505,12 +505,14 @@ public class BitcoinWalletManager: WalletManager { }}) self.coreWalletManager = BRWalletManagerNew (client, - forkId, account.masterPublicKey, params, UInt32 (timestamp), path) -#endif + + self.corePeerManager = BRWalletManagerGetPeerManager (self.coreWalletManager) + self.coreWallet = BRWalletManagerGetWallet(self.coreWalletManager) +#else self.coreWallet = BRWalletNew (nil, 0, account.masterPublicKey, Int32(forkId.rawValue)) self.corePeerManager = BRPeerManagerNew (params, coreWallet, UInt32(timestamp), @@ -662,7 +664,7 @@ public class BitcoinWalletManager: WalletManager { { (this) in // threadCleanup if let _ = BitcoinWalletManager.lookup (ptr: this) { }}) - + #endif BitcoinWalletManager.managers.append(self) self.listener.handleManagerEvent(manager: self, event: WalletManagerEvent.created) @@ -670,14 +672,14 @@ public class BitcoinWalletManager: WalletManager { } public func connect() { - #if false + #if true BRWalletManagerConnect(self.coreWalletManager) #endif BRPeerManagerConnect (self.corePeerManager) } public func disconnect() { - #if false + #if true BRWalletManagerDisconnect(self.coreWalletManager) #endif BRPeerManagerDisconnect (self.corePeerManager) diff --git a/Swift/BRCryptoDemo/AppDelegate.swift b/Swift/BRCryptoDemo/AppDelegate.swift index db83b3d51..9d341fe40 100644 --- a/Swift/BRCryptoDemo/AppDelegate.swift +++ b/Swift/BRCryptoDemo/AppDelegate.swift @@ -63,6 +63,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele .appendingPathComponent("Core").path do { + if FileManager.default.fileExists(atPath: storagePath) { + try FileManager.default.removeItem(atPath: storagePath) + } + try FileManager.default.createDirectory (atPath: storagePath, withIntermediateDirectories: true, attributes: nil) @@ -71,6 +75,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele print("Error: \(error.localizedDescription)") } + NSLog ("StoragePath: \(storagePath)"); + self.listener = CoreDemoListener () self.btcManager = BitcoinWalletManager (listener: listener, diff --git a/ethereum/ewm/BREthereumEWM.c b/ethereum/ewm/BREthereumEWM.c index 26b89900a..560b67de9 100644 --- a/ethereum/ewm/BREthereumEWM.c +++ b/ethereum/ewm/BREthereumEWM.c @@ -45,6 +45,8 @@ // When using a BRD sync offset the start block by 3 days of Ethereum blocks #define EWM_BRD_SYNC_START_BLOCK_OFFSET (3 * 24 * 60 * 4) /* 4 per minute, every 15 seconds */ +#define EWM_INITIAL_SET_SIZE_DEFAULT (25) + /* Forward Declaration */ static void ewmPeriodicDispatcher (BREventHandler handler, @@ -107,8 +109,11 @@ fileServiceTypeTransactionV1Reader (BRFileServiceContext context, static BRSetOf(BREthereumTransaction) initialTransactionsLoad (BREthereumEWM ewm) { - BRSetOf(BREthereumTransaction) transactions = BRSetNew(transactionHashValue, transactionHashEqual, 100); - fileServiceLoad (ewm->fs, transactions, fileServiceTypeTransactions, 1); + BRSetOf(BREthereumTransaction) transactions = BRSetNew(transactionHashValue, transactionHashEqual, EWM_INITIAL_SET_SIZE_DEFAULT); + if (1 != fileServiceLoad (ewm->fs, transactions, fileServiceTypeTransactions, 1)) { + BRSetFree(transactions); + return NULL; + } return transactions; } @@ -167,8 +172,11 @@ fileServiceTypeLogV1Reader (BRFileServiceContext context, static BRSetOf(BREthereumLog) initialLogsLoad (BREthereumEWM ewm) { - BRSetOf(BREthereumLog) logs = BRSetNew(logHashValue, logHashEqual, 100); - fileServiceLoad (ewm->fs, logs, fileServiceTypeLogs, 1); + BRSetOf(BREthereumLog) logs = BRSetNew(logHashValue, logHashEqual, EWM_INITIAL_SET_SIZE_DEFAULT); + if (1 != fileServiceLoad (ewm->fs, logs, fileServiceTypeLogs, 1)) { + BRSetFree(logs); + return NULL; + } return logs; } @@ -227,8 +235,11 @@ fileServiceTypeBlockV1Reader (BRFileServiceContext context, static BRSetOf(BREthereumBlock) initialBlocksLoad (BREthereumEWM ewm) { - BRSetOf(BREthereumBlock) blocks = BRSetNew(blockHashValue, blockHashEqual, 100); - fileServiceLoad (ewm->fs, blocks, fileServiceTypeBlocks, 1); + BRSetOf(BREthereumBlock) blocks = BRSetNew(blockHashValue, blockHashEqual, EWM_INITIAL_SET_SIZE_DEFAULT); + if (1 != fileServiceLoad (ewm->fs, blocks, fileServiceTypeBlocks, 1)) { + BRSetFree(blocks); + return NULL; + } return blocks; } @@ -287,11 +298,47 @@ fileServiceTypeNodeV1Reader (BRFileServiceContext context, static BRSetOf(BREthereumNodeConfig) initialNodesLoad (BREthereumEWM ewm) { - BRSetOf(BREthereumNodeConfig) nodes = BRSetNew(nodeConfigHashValue, nodeConfigHashEqual, 100); - fileServiceLoad (ewm->fs, nodes, fileServiceTypeNodes, 1); + BRSetOf(BREthereumNodeConfig) nodes = BRSetNew(nodeConfigHashValue, nodeConfigHashEqual, EWM_INITIAL_SET_SIZE_DEFAULT); + if (1 != fileServiceLoad (ewm->fs, nodes, fileServiceTypeNodes, 1)) { + BRSetFree(nodes); + return NULL; + } return nodes; } + +/** + * + * + * @param context The EthereumWalletManager (EWM) + * @param fs the FileSerice + * @param error A BRFileServiceError + */ +static void +ewmFileServiceErrorHandler (BRFileServiceContext context, + BRFileService fs, + BRFileServiceError error) { + //BREthereumEWM ewm = (BREthereumEWM) context; + + switch (error.type) { + case FILE_SERVICE_IMPL: + // This actually a FATAL - an unresolvable coding error. + eth_log ("EWM", "FileService Error: IMPL: %s", error.u.impl.reason); + break; + case FILE_SERVICE_UNIX: + eth_log ("EWM", "FileService Error: UNIX: %s", strerror(error.u.unix.error)); + break; + case FILE_SERVICE_ENTITY: + // This is likely a coding error too. + eth_log ("EWM", "FileService Error: ENTITY (%s): %s", + error.u.entity.type, + error.u.entity.reason); + break; + } + eth_log ("EWM", "FileService Error: FORCED SYNC%s", ""); + + // TODO: Actually force a resync. +} /// /// MARK: Ethereum Wallet Manager /// @@ -329,7 +376,9 @@ ewmCreate (BREthereumNetwork network, // The file service. Initialize {nodes, blocks, transactions and logs} from the FileService - ewm->fs = fileServiceCreate (storagePath, networkGetName(network), "eth"); + ewm->fs = fileServiceCreate (storagePath, networkGetName(network), "eth", + ewm, + ewmFileServiceErrorHandler); if (NULL == ewm->fs) { free (ewm); return NULL; } /// Transaction @@ -341,7 +390,6 @@ ewmCreate (BREthereumNetwork network, fileServiceTypeTransactionV1Writer); fileServiceDefineCurrentVersion (ewm->fs, fileServiceTypeTransactions, EWM_TRANSACTION_VERSION_1); - BRSetOf(BREthereumTransaction) transactions = initialTransactionsLoad(ewm); /// Log fileServiceDefineType (ewm->fs, fileServiceTypeLogs, @@ -352,7 +400,6 @@ ewmCreate (BREthereumNetwork network, fileServiceTypeLogV1Writer); fileServiceDefineCurrentVersion (ewm->fs, fileServiceTypeLogs, EWM_LOG_VERSION_1); - BRSetOf(BREthereumLog) logs = initialLogsLoad(ewm); /// Peer fileServiceDefineType (ewm->fs, fileServiceTypeNodes, @@ -363,7 +410,6 @@ ewmCreate (BREthereumNetwork network, fileServiceTypeNodeV1Writer); fileServiceDefineCurrentVersion (ewm->fs, fileServiceTypeNodes, EWM_NODE_VERSION_1); - BRSetOf(BREthereumNodeConfig) nodes = initialNodesLoad(ewm); /// Block fileServiceDefineType (ewm->fs, fileServiceTypeBlocks, @@ -374,8 +420,31 @@ ewmCreate (BREthereumNetwork network, fileServiceTypeBlockV1Writer); fileServiceDefineCurrentVersion (ewm->fs, fileServiceTypeBlocks, EWM_BLOCK_VERSION_1); + + // Load all the persistent entities + BRSetOf(BREthereumTransaction) transactions = initialTransactionsLoad(ewm); + BRSetOf(BREthereumLog) logs = initialLogsLoad(ewm); + BRSetOf(BREthereumNodeConfig) nodes = initialNodesLoad(ewm); BRSetOf(BREthereumBlock) blocks = initialBlocksLoad(ewm); + // If any are NULL, then we have an error and a full sync is required. The sync will be + // started automatically, as part of the normal processing, of 'blocks' (we'll use a checkpoint, + // before the `accountTimestamp, which will be well in the past and we'll sync up to the + // head of the blockchain). + if (NULL == transactions || NULL == logs || NULL == nodes || NULL == blocks) { + if (NULL == transactions) transactions = BRSetNew(transactionHashValue, transactionHashEqual, EWM_INITIAL_SET_SIZE_DEFAULT); + else BRSetClear(transactions); + + if (NULL == logs) logs = BRSetNew(logHashValue, logHashEqual, EWM_INITIAL_SET_SIZE_DEFAULT); + else BRSetClear(logs); + + if (NULL == blocks) blocks = BRSetNew(blockHashValue, blockHashEqual, EWM_INITIAL_SET_SIZE_DEFAULT); + else BRSetClear(blocks); + + if (NULL == nodes) nodes = BRSetNew(nodeConfigHashValue, nodeConfigHashEqual, EWM_INITIAL_SET_SIZE_DEFAULT); + else BRSetClear(nodes); + } + // If we have no blocks; then add a checkpoint if (0 == BRSetCount(blocks)) { const BREthereumBlockCheckpoint *checkpoint = blockCheckpointLookupByTimestamp (network, accountTimestamp); @@ -457,10 +526,9 @@ ewmCreate (BREthereumNetwork network, blockGetNumber (lastBlock), blockGetTimestamp (lastBlock)); - // ... and then ignore nodes + // ... and then just ignore nodes - // TODO: What items to free? - BRSetFree (nodes); + // Free sets... BUT DO NOT free 'nodes' as those had 'OwnershipGiven' in bcsCreate() BRSetFree (blocks); BRSetFree (transactions); BRSetFree (logs); @@ -474,7 +542,7 @@ ewmCreate (BREthereumNetwork network, break; } - case P2P_WITH_BRD_SYNC: + case P2P_WITH_BRD_SYNC: // case P2P_ONLY: { ewm->bcs = bcsCreate (network, accountGetPrimaryAddress (account), diff --git a/support/BRFileService.c b/support/BRFileService.c index 197f2cc84..e5148a1f6 100644 --- a/support/BRFileService.c +++ b/support/BRFileService.c @@ -29,6 +29,7 @@ #include #include #include +#include #if !defined(BRArrayOf) #define BRArrayOf(type) type* @@ -106,12 +107,16 @@ fileServiceEntityTypeAddHandler (BRFileServiceEntityType *entityType, struct BRFileServiceRecord { const char *pathToType; BRArrayOf(BRFileServiceEntityType) entityTypes; + BRFileServiceContext context; + BRFileServiceErrorHandler handler; }; extern BRFileService fileServiceCreate (const char *basePath, const char *network, - const char *currency) { + const char *currency, + BRFileServiceContext context, + BRFileServiceErrorHandler handler) { // Reasonable limits on `network` and `currency` (ensure subsequent stack allocation works). if (strlen(network) > FILENAME_MAX || strlen(currency) > FILENAME_MAX) return NULL; @@ -138,6 +143,8 @@ fileServiceCreate (const char *basePath, fs->pathToType = strdup(dirPath); array_new (fs->entityTypes, FILE_SERVICE_INITIAL_TYPE_COUNT); + fileServiceSetErrorHandler (fs, context, handler); + return fs; } @@ -152,6 +159,14 @@ fileServiceRelease (BRFileService fs) { free (fs); } +extern void +fileServiceSetErrorHandler (BRFileService fs, + BRFileServiceContext context, + BRFileServiceErrorHandler handler) { + fs->context = context; + fs->handler = handler; +} + static BRFileServiceEntityType * fileServiceLookupType (const BRFileService fs, const char *type) { @@ -185,16 +200,70 @@ fileServiceLookupEntityHandler (const BRFileService fs, return (NULL == entityType ? NULL : fileServiceEntityTypeLookupHandler (entityType, version)); } -extern void /* error code? or return 'results' (instead of filling `results`) */ +/// +/// MARK: Load +/// +static int +fileServiceLoadFailedInternal (BRFileService fs, + void* bufferToFree, + FILE* fileToClose, + BRFileServiceError error) { + if (NULL != bufferToFree) free (bufferToFree); + if (NULL != fileToClose) fclose (fileToClose); + + if (NULL != fs->handler) + fs->handler (fs->context, fs, error); + + return 0; +} + +static int +fileServiceLoadFailedImpl(BRFileService fs, + void* bufferToFree, + FILE* fileToClose, + const char *reason) { + return fileServiceLoadFailedInternal (fs, bufferToFree, fileToClose, + (BRFileServiceError) { + FILE_SERVICE_IMPL, + { .impl = { reason }} + }); +} + +static int +fileServiceLoadFailedUnix(BRFileService fs, + void* bufferToFree, + FILE* fileToClose, + int error) { + return fileServiceLoadFailedInternal (fs, bufferToFree, fileToClose, + (BRFileServiceError) { + FILE_SERVICE_UNIX, + { .unix = { error }} + }); +} + +static int +fileServiceLoadFailedEntity(BRFileService fs, + void* bufferToFree, + FILE* fileToClose, + const char *type, + const char *reason) { + return fileServiceLoadFailedInternal (fs, bufferToFree, fileToClose, + (BRFileServiceError) { + FILE_SERVICE_ENTITY, + { .entity = { type, reason }} + }); +} + +extern int fileServiceLoad (BRFileService fs, BRSet *results, const char *type, - int updateVersion) { /* blocks, peers, transactions, logs, ... */ + int updateVersion) { BRFileServiceEntityType *entityType = fileServiceLookupType (fs, type); - if (NULL == entityType) return; + if (NULL == entityType) return fileServiceLoadFailedImpl (fs, NULL, NULL, "missed type"); BRFileServiceEntityHandler *entityHandlerCurrent = fileServiceEntityTypeLookupHandler(entityType, entityType->currentVersion); - if (NULL == entityHandlerCurrent) return; + if (NULL == entityHandlerCurrent) return fileServiceLoadFailedImpl (fs, NULL, NULL, "missed type handler"); DIR *dir; struct dirent *dirEntry; @@ -204,10 +273,8 @@ fileServiceLoad (BRFileService fs, char filename[strlen(dirPath) + 1 + 2 * sizeof(UInt256) + 1]; - if (-1 == directoryMake(dirPath) || NULL == (dir = opendir(dirPath))) { - //*error = errno; - return; - } + if (-1 == directoryMake(dirPath) || NULL == (dir = opendir(dirPath))) + return fileServiceLoadFailedUnix (fs, NULL, NULL, errno); // Allocate some storage for entity bytes; size_t bufferSize = 8 * 1024; @@ -218,24 +285,26 @@ fileServiceLoad (BRFileService fs, if (dirEntry->d_type == DT_REG) { sprintf (filename, "%s/%s", dirPath, dirEntry->d_name); FILE *file = fopen (filename, "rb"); + if (NULL == file) return fileServiceLoadFailedUnix (fs, buffer, NULL, errno); + BRFileServiceVersion version; uint32_t bytesCount; // read the header version BRFileServiceHeaderFormatVersion headerVersion; - fread (&headerVersion, sizeof(BRFileServiceHeaderFormatVersion), 1, file); + if (1 != fread (&headerVersion, sizeof(BRFileServiceHeaderFormatVersion), 1, file)) + return fileServiceLoadFailedUnix (fs, buffer, file, errno); // read the header switch (headerVersion) { case HEADER_FORMAT_1: { // read the version - fread (&version, sizeof(BRFileServiceVersion), 1, file); - - // read the checksum - - // read the bytesCount - fread (&bytesCount, sizeof(uint32_t), 1, file); + if (1 != fread (&version, sizeof(BRFileServiceVersion), 1, file) || + // read the checksum + // read the bytesCount + 1 != fread (&bytesCount, sizeof(uint32_t), 1, file)) + return fileServiceLoadFailedUnix (fs, buffer, file, errno); break; } @@ -248,12 +317,14 @@ fileServiceLoad (BRFileService fs, } // read the bytes - multiple might be required - fread (buffer, 1, bytesCount, file); + if (bytesCount != fread (buffer, 1, bytesCount, file)) + return fileServiceLoadFailedUnix (fs, buffer, file, errno); // All file reading is complete; next read should be EOF. // Done with file. - fclose (file); + if (0 != fclose (file)) + return fileServiceLoadFailedUnix (fs, buffer, NULL, errno); // We now have everything @@ -270,10 +341,13 @@ fileServiceLoad (BRFileService fs, // Look up the entity handler BRFileServiceEntityHandler *handler = fileServiceEntityTypeLookupHandler(entityType, version); - if (NULL == handler) /* trouble */ break; + if (NULL == handler) return fileServiceLoadFailedImpl (fs, buffer, NULL, "missed type handler"); // Read the entity from buffer and add to results. void *entity = handler->reader (handler->context, fs, buffer, bytesCount); + if (NULL == entity) return fileServiceLoadFailedEntity (fs, buffer, NULL, type, "reader"); + + // Update restuls with the newly restored entity BRSetAdd (results, entity); // If the read version is not the current version, update @@ -285,6 +359,8 @@ fileServiceLoad (BRFileService fs, free (buffer); closedir (dir); + + return 1; } extern void /* error code? */ @@ -306,26 +382,30 @@ fileServiceSave (BRFileService fs, sprintf (filename, "%s/%s/%s", fs->pathToType, type, u256hex(identifier)); FILE *file = fopen (filename, "wb"); + if (NULL == file) { + + } // Always, always write the header for the currentHeaderFormatVersion - // write the header version - fwrite(¤tHeaderFormatVersion, sizeof(BRFileServiceHeaderFormatVersion), 1, file); + if (// write the header version + 1 != fwrite(¤tHeaderFormatVersion, sizeof(BRFileServiceHeaderFormatVersion), 1, file) || + // then the version + 1 != fwrite (&entityType->currentVersion, sizeof(BRFileServiceVersion), 1, file) || + // then the checksum? + // write the bytesCount + 1 != fwrite(&bytesCount, sizeof (uint32_t), 1, file)) { - // write the version - fwrite (&entityType->currentVersion, sizeof(BRFileServiceVersion), 1, file); + } - // write 'currentHeaderFormatVersion'-specific data - // compute the checksum - // write the checksum + // write the bytes. + if (bytesCount != fwrite(bytes, 1, bytesCount, file)) { - // write the bytes count - fwrite(&bytesCount, sizeof (uint32_t), 1, file); + } - // write the bytes. - fwrite(bytes, 1, bytesCount, file); + if (0 != fclose (file)) { - fclose (file); + } free (bytes); } diff --git a/support/BRFileService.h b/support/BRFileService.h index 4ab662434..78831d36c 100644 --- a/support/BRFileService.h +++ b/support/BRFileService.h @@ -42,18 +42,70 @@ // typedef struct BRFileServiceRecord *BRFileService; +/// A context used in callbacks +typedef void* BRFileServiceContext; + +typedef enum { + FILE_SERVICE_IMPL, // generally a fatal condition + FILE_SERVICE_UNIX, // something in the file system (fopen, fwrite, ... errorred) + FILE_SERVICE_ENTITY // entity read/write (parse/serialize) error +} BRFileServiceErrorType; + +typedef struct { + BRFileServiceErrorType type; + union { + struct { + const char *reason; + } impl; + + struct { + int error; + } unix; + + struct { + const char *type; + const char *reason; + } entity; + } u; +} BRFileServiceError; + +typedef void +(*BRFileServiceErrorHandler) (BRFileServiceContext context, + BRFileService fs, + BRFileServiceError error); + + /// This *must* be the same fixed size type forever. It is uint8_t. typedef uint8_t BRFileServiceVersion; extern BRFileService fileServiceCreate (const char *basePath, const char *network, - const char *currency); + const char *currency, + BRFileServiceContext context, + BRFileServiceErrorHandler handler); extern void fileServiceRelease (BRFileService fs); -extern void /* error code? or return 'results' (instead of filling `results`) */ +extern void +fileServiceSetErrorHandler (BRFileService fs, + BRFileServiceContext context, + BRFileServiceErrorHandler handler); + +/** + * Load all entities of `type` adding each to `results`. If there is an error then the + * fileServices' error handler is invoked and 0 is returned + * + * @param fs The fileServie + * @param results A BRSet within which to store the results. The type stored in the BRSet must + * be consistent with type recovered from the file system. + * @param type The type to restore + * @param updateVersion If true (1) update old versions with newer ones. + * + * @return true (1) if success, false (0) otherwise; + */ +extern int fileServiceLoad (BRFileService fs, BRSet *results, const char *type, /* blocks, peers, transactions, logs, ... */ @@ -76,8 +128,6 @@ fileServiceClear (BRFileService fs, extern void fileServiceClearAll (BRFileService fs); -typedef void* BRFileServiceContext; - typedef UInt256 (*BRFileServiceIdentifier) (BRFileServiceContext context, BRFileService fs,