             block?.pointee.merkleRoot = (sqlite3_column_blob(sql, 9)?.assumingMemoryBound(to: UInt256.self).pointee)!
             block?.pointee.prevBlock = (sqlite3_column_blob(sql, 10)?.assumingMemoryBound(to: UInt256.self).pointee)!
             blocks.append(block)
-        }
-        
-        if sqlite3_finalize(sql) != SQLITE_OK {
-            print(String(cString: sqlite3_errmsg(db)))
-        }
-        
+            r = sqlite3_step(sql)
+        }
+        
+        if r == SQLITE_DONE { r = sqlite3_finalize(sql) }
+        if r != SQLITE_OK { print(String(cString: sqlite3_errmsg(db))) }
         return blocks
     }
     
     private func saveBlocks(blocks: [UnsafeMutablePointer<BRMerkleBlock>?]) {
-        // TODO: XXX implement
+        var sql: OpaquePointer? = nil
+        var pk: Int32 = 0
+        var r: Int32
+        
+        r = sqlite3_exec(db, "begin exclusive", nil, nil, nil)
+        if r == SQLITE_OK && blocks.count > 1 {
+            r = sqlite3_exec(db, "delete from ZBRMERKLEBLOCKENTITY", nil, nil, nil)
+        }
+        else if r == SQLITE_OK {
+            r = sqlite3_prepare_v2(db, "select Z_MAX from Z_PRIMARYKEY where Z_ENT = \(blockEnt)", -1, &sql, nil)
+            if r == SQLITE_OK { r = sqlite3_step(sql) }
+            if r == SQLITE_ROW {
+                pk = sqlite3_column_int(sql, 0)
+                r = sqlite3_finalize(sql)
+            }
+        }
+        if r == SQLITE_OK {
+            r = sqlite3_prepare_v2(db, "insert into ZBRMERKLEBLOCKENTITY (Z_PK, Z_ENT, Z_OPT, ZHEIGHT, ZNONCE, " +
+                "ZTARGET, ZTOTALTRANSACTIONS, ZVERSION, ZTIMESTAMP, ZBLOCKHASH, ZFLAGS, ZHASHES, ZMERKLEROOT, " +
+                "ZPREVBLOCK) values (?, \(blockEnt), 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", -1, &sql, nil)
+        }
+        
+        for b in blocks {
+            pk = pk + 1
+            if r == SQLITE_OK { r = sqlite3_bind_int(sql, 1, pk) }
+            if r == SQLITE_OK { r = sqlite3_bind_int(sql, 2, Int32(bitPattern: b!.pointee.height)) }
+            if r == SQLITE_OK { r = sqlite3_bind_int(sql, 3, Int32(bitPattern: b!.pointee.nonce)) }
+            if r == SQLITE_OK { r = sqlite3_bind_int(sql, 4, Int32(bitPattern: b!.pointee.target)) }
+            if r == SQLITE_OK { r = sqlite3_bind_int(sql, 5, Int32(bitPattern: b!.pointee.totalTx)) }
+            if r == SQLITE_OK { r = sqlite3_bind_int(sql, 6, Int32(bitPattern: b!.pointee.version)) }
+            if r == SQLITE_OK { r = sqlite3_bind_int(sql, 7, Int32(bitPattern: b!.pointee.timestamp)) }
+            if r == SQLITE_OK {
+                r = sqlite3_bind_blob(sql, 8, [b!.pointee.blockHash], Int32(MemoryLayout<UInt256>.size),
+                                      SQLITE_TRANSIENT)
+            }
+            if r == SQLITE_OK {
+                r = sqlite3_bind_blob(sql, 9, [b!.pointee.flags], Int32(b!.pointee.flagsLen), SQLITE_TRANSIENT)
+            }
+            if r == SQLITE_OK {
+                r = sqlite3_bind_blob(sql, 10, [b!.pointee.hashes],
+                                      Int32(MemoryLayout<UInt256>.size*b!.pointee.hashesCount), SQLITE_TRANSIENT)
+            }
+            if r == SQLITE_OK {
+                r = sqlite3_bind_blob(sql, 11, [b!.pointee.merkleRoot], Int32(MemoryLayout<UInt256>.size),
+                                      SQLITE_TRANSIENT)
+            }
+            if r == SQLITE_OK {
+                r = sqlite3_bind_blob(sql, 12, [b!.pointee.prevBlock], Int32(MemoryLayout<UInt256>.size),
+                                      SQLITE_TRANSIENT)
+            }
+            if r == SQLITE_OK { r = sqlite3_step(sql) }
+            if r == SQLITE_DONE { r = sqlite3_reset(sql) }
+        }
+        
+        if r == SQLITE_OK {
+            r = sqlite3_exec(db, "update or fail Z_PRIMARYKEY set Z_MAX = \(pk) where Z_ENT = \(blockEnt)",
+                nil, nil, nil)
+        }
+        if r == SQLITE_OK { r = sqlite3_exec(db, "commit", nil, nil, nil) }
+        if r == SQLITE_OK { r = sqlite3_finalize(sql) }
+        if r != SQLITE_OK { print(String(cString: sqlite3_errmsg(db))) }
     }
     
     private func loadPeers() -> [BRPeer] {
         var sql: OpaquePointer? = nil
         var peers = [BRPeer]()
-
-        if sqlite3_prepare_v2(db, "select ZADDRESS, ZPORT, ZSERVICES, ZTIMESTAMP from ZBRPEERENTITY",
-                              -1, &sql, nil) != SQLITE_OK {
-            print(String(cString: sqlite3_errmsg(db)))
-        }
-        
-        while sqlite3_step(sql) == SQLITE_ROW {
+        var r: Int32
+
+        r = sqlite3_prepare_v2(db, "select ZADDRESS, ZPORT, ZSERVICES, ZTIMESTAMP from ZBRPEERENTITY", -1, &sql, nil)
+        if r == SQLITE_OK { r = sqlite3_step(sql) }
+        
+        while r == SQLITE_ROW {
             var peer = BRPeer()
             
-            peer.address = UInt128(u32: (0, 0, UInt32(bigEndian: 0xffff),
-                                         UInt32(bigEndian: UInt32(sqlite3_column_int(sql, 0)))))
-            peer.port = UInt16(sqlite3_column_int(sql, 1))
-            peer.services = UInt64(sqlite3_column_int64(sql, 2))
-            peer.timestamp = UInt64(sqlite3_column_int64(sql, 3))
+            peer.address = UInt128(u32: (0, 0, UInt32(0xffff).bigEndian,
+                                         UInt32(bitPattern: sqlite3_column_int(sql, 0)).bigEndian))
+            peer.port = UInt16(truncatingBitPattern: sqlite3_column_int(sql, 1))
+            peer.services = UInt64(bitPattern: sqlite3_column_int64(sql, 2))
+            peer.timestamp = UInt64(bitPattern: sqlite3_column_int64(sql, 3))
             peers.append(peer)
-        }
-        
-        if sqlite3_finalize(sql) != SQLITE_OK {
-            print(String(cString: sqlite3_errmsg(db)))
-        }
-        
+            r = sqlite3_step(sql)
+        }
+        
+        if r == SQLITE_DONE { r = sqlite3_finalize(sql) }
+        if r != SQLITE_OK { print(String(cString: sqlite3_errmsg(db))) }
         return peers
     }
     
-    private func savePeers(blocks: [BRPeer]) {
-        // TODO: XXX implement
+    private func savePeers(peers: [BRPeer]) {
+        var sql: OpaquePointer? = nil
+        var pk: Int32 = 0
+        var r: Int32
+        
+        r = sqlite3_exec(db, "begin exclusive", nil, nil, nil)
+        if r == SQLITE_OK && peers.count > 1 {
+            r = sqlite3_exec(db, "delete from ZBRPEERENTITY", nil, nil, nil)
+        }
+        else if r == SQLITE_OK {
+            r = sqlite3_prepare_v2(db, "select Z_MAX from Z_PRIMARYKEY where Z_ENT = \(peerEnt)", -1, &sql, nil)
+            if r == SQLITE_OK { r = sqlite3_step(sql) }
+            if r == SQLITE_ROW {
+                pk = sqlite3_column_int(sql, 0)
+                r = sqlite3_finalize(sql)
+            }
+        }
+        if r == SQLITE_OK {
+            r = sqlite3_prepare_v2(db, "insert into ZBRPEERENTITY (Z_PK, Z_ENT, Z_OPT, ZADDRESS, ZMISBEHAVIN, ZPORT," +
+                "ZSERVICES, ZTIMESTAMP) values (?, \(peerEnt), 1, ?, 0, ?, ?, ?)", -1, &sql, nil)
+        }
+        
+        for p in peers {
+            pk = pk + 1
+            if r == SQLITE_OK { r = sqlite3_bind_int(sql, 1, pk) }
+            if r == SQLITE_OK { r = sqlite3_bind_int(sql, 2, peerEnt) }
+            if r == SQLITE_OK { r = sqlite3_bind_int(sql, 3, Int32(bitPattern: p.address.u32.3)) }
+            if r == SQLITE_OK { r = sqlite3_bind_int(sql, 4, Int32(p.port)) }
+            if r == SQLITE_OK { r = sqlite3_bind_int64(sql, 5, Int64(bitPattern: p.services)) }
+            if r == SQLITE_OK { r = sqlite3_bind_int64(sql, 6, Int64(bitPattern: p.timestamp)) }
+            if r == SQLITE_OK { r = sqlite3_step(sql) }
+            if r == SQLITE_DONE { r = sqlite3_reset(sql) }
+        }
+        
+        if r == SQLITE_OK {
+            r = sqlite3_exec(db, "update or fail Z_PRIMARYKEY set Z_MAX = \(pk) where Z_ENT = \(peerEnt)",
+                nil, nil, nil)
+        }
+        if r == SQLITE_OK { r = sqlite3_exec(db, "commit", nil, nil, nil) }
+        if r == SQLITE_OK { r = sqlite3_finalize(sql) }
+        if r != SQLITE_OK { print(String(cString: sqlite3_errmsg(db))) }
     }
     
     private func isNetworkReachable() -> Bool {

            tx?.pointee.timestamp = (buf?.load(fromByteOffset: len - MemoryLayout<UInt32>.size,
                                               as: UInt32.self).littleEndian)!
            transactions.append(tx)
        }
        
        if sqlite3_finalize(sql) != SQLITE_OK {
            print(String(cString: sqlite3_errmsg(db)))
        }
        
        return transactions
    }
    

            "ZMISBEHAVIN integer," +
            "ZPORT integer," +
            "ZSERVICES integer," +
            "ZTIMESTAMP timestamp)", nil, nil, nil)
        if r == SQLITE_OK {
            r = sqlite3_exec(db, "create index if not exists ZBRPEERENTITY_ZADDRESS_INDEX on ZBRPEERENTITY (ZADDRESS)",
                             nil, nil, nil)
        }
        if r == SQLITE_OK {
            r = sqlite3_exec(db, "create index if not exists ZBRPEERENTITY_ZMISBEHAVIN_INDEX " +
                "on ZBRPEERENTITY (ZMISBEHAVIN)", nil, nil, nil)
        }
        if r == SQLITE_OK {
            r = sqlite3_exec(db, "create index if not exists ZBRPEERENTITY_ZPORT_INDEX on ZBRPEERENTITY (ZPORT)",
                             nil, nil, nil)
        }
        if r == SQLITE_OK {
            r = sqlite3_exec(db, "create index if not exists ZBRPEERENTITY_ZTIMESTAMP_INDEX " +
                "on ZBRPEERENTITY (ZTIMESTAMP)", nil, nil, nil)
        }
        if r != SQLITE_OK { print(String(cString: sqlite3_errmsg(db))) }

        // primary keys
        r = sqlite3_exec(db, "create table if not exists Z_PRIMARYKEY (" +
            "Z_ENT INTEGER PRIMARY KEY," +
            "Z_NAME VARCHAR," +
            "Z_SUPER INTEGER," +
            "Z_MAX INTEGER)", nil, nil, nil)
        if r == SQLITE_OK {
            r = sqlite3_exec(db, "insert into Z_PRIMARYKEY (Z_ENT, Z_NAME, Z_SUPER, Z_MAX) " +
                "select 6, 'BRTxMetadataEntity', 0, 0 except" +
                "select 6, Z_NAME, 0, 0 from Z_PRIMARYKEY where Z_NAME = 'BRTxMetadataEntity'", nil, nil, nil)
        }
        if r == SQLITE_OK {
            r = sqlite3_exec(db, "insert into Z_PRIMARYKEY (Z_ENT, Z_NAME, Z_SUPER, Z_MAX) " +
                "select 2, 'BRMerkleBlockEntity', 0, 0 except" +
                "select 2, Z_NAME, 0, 0 from Z_PRIMARYKEY where Z_NAME = 'BRMerkleBlockEntity'", nil, nil, nil)
        }
        if r == SQLITE_OK {
            r = sqlite3_exec(db, "insert into Z_PRIMARYKEY (Z_ENT, Z_NAME, Z_SUPER, Z_MAX) " +
                "select 3, 'BRPeerEntity', 0, 0 except" +
                "select 3, Z_NAME, 0, 0 from Z_PRIMARYKEY where Z_NAME = 'BRPeerEntity'", nil, nil, nil)
        }
        if r == SQLITE_OK { r = sqlite3_prepare_v2(db, "select Z_ENT, Z_NAME from Z_PRIMARYKEY", -1, &sql, nil) }
        if r == SQLITE_OK { r = sqlite3_step(sql) }
        
        while r == SQLITE_ROW {
            let name = String(cString: sqlite3_column_text(sql, 1))
            
            if name == "BRTxMetadataEntity" { txEnt = sqlite3_column_int(sql, 0) }
            else if name == "BRTxMerkleBlockEntity" { blockEnt = sqlite3_column_int(sql, 0) }
            else if name == "BRPeerEntity" { peerEnt = sqlite3_column_int(sql, 0) }
            r = sqlite3_step(sql)
        }
        
        if r == SQLITE_DONE { r = sqlite3_finalize(sql) }
        if r != SQLITE_OK { print(String(cString: sqlite3_errmsg(db))) }
    }
    
    private func loadTransactions() -> [UnsafeMutablePointer<BRTransaction>?] {
        var sql: OpaquePointer? = nil
        var transactions = [UnsafeMutablePointer<BRTransaction>?]()
        var r: Int32

        r = sqlite3_prepare_v2(db, "select ZBLOB from ZBRTXMETADATAENTITY where ZTYPE = 1", -1, &sql, nil)
        if r == SQLITE_OK { r = sqlite3_step(sql) }
        
        while r == SQLITE_ROW {
            let buf = sqlite3_column_blob(sql, 0)
            let len = Int(sqlite3_column_bytes(sql, 0))
            let tx = BRTransactionParse(buf?.assumingMemoryBound(to: UInt8.self), len - MemoryLayout<UInt32>.size*2)
