diff --git a/bitherj b/bitherj index ea5c711..6bc910d 160000 --- a/bitherj +++ b/bitherj @@ -1 +1 @@ -Subproject commit ea5c711218ca3954e31fcb94558ca24341f773c0 +Subproject commit 6bc910d0e3b1793e2beb35d578982bba7e98eee5 diff --git a/src/main/java/net/bither/Bither.java b/src/main/java/net/bither/Bither.java index ac86356..f894fae 100755 --- a/src/main/java/net/bither/Bither.java +++ b/src/main/java/net/bither/Bither.java @@ -21,7 +21,12 @@ import net.bither.bitherj.BitherjSettings; import net.bither.bitherj.core.Address; import net.bither.bitherj.core.AddressManager; +import net.bither.bitherj.crypto.ECKey; import net.bither.bitherj.crypto.mnemonic.MnemonicCode; +import net.bither.bitherj.exception.AddressFormatException; +import net.bither.bitherj.qrcode.QRCodeUtil; +import net.bither.bitherj.utils.Base58; +import net.bither.bitherj.utils.Utils; import net.bither.db.AddressDBHelper; import net.bither.db.DesktopDbImpl; import net.bither.db.TxDBHelper; @@ -37,6 +42,7 @@ import net.bither.platform.listener.GenericOpenURIEvent; import net.bither.preference.UserPreference; import net.bither.runnable.RunnableListener; +import net.bither.service.Server; import net.bither.utils.*; import net.bither.viewsystem.CoreController; import net.bither.viewsystem.MainFrame; @@ -94,6 +100,13 @@ public static void main(String args[]) { applicationDataDirectoryLocator = new ApplicationDataDirectoryLocator(); initBitherApplication(); initApp(args); +// try { +// boolean reslt = ECKey.verify(Utils.hexStringToByteArray("F7FBD709F5CDD0EE6020DB5B123F5A546B4649219E50F6F36AA70001CC41257F"), Utils.hexStringToByteArray("3044022011C8706BBA640A47514B65F2B6EE102CF1387426777B6C31812EDC72FED057A2022074D37A9C49BF69D71A0BB6A61977744C4405E332DF796DCDF3A98157921EF340"), Base58.decode +// ("2283VfwfS2A2vNPQktF3ZSo3QXpw2Lx72SMvDivAxmC9R")); +// System.out.println("result:" + reslt); +// }catch (AddressFormatException e){ +// e.printStackTrace(); +// } // new Thread(new Runnable() { // @Override // public void run() { @@ -397,7 +410,12 @@ private static void initApp(final String args[]) { // Enclosing try to enable graceful closure for unexpected errors. fixJavaBug(); - + try { + Server.main(); + } catch (IOException e) { + e.printStackTrace(); + System.exit(-1); + } if (SwingUtilities.isEventDispatchThread()) { initController(args); diff --git a/src/main/java/net/bither/BitherUI.java b/src/main/java/net/bither/BitherUI.java index 98f2c1f..e77819a 100755 --- a/src/main/java/net/bither/BitherUI.java +++ b/src/main/java/net/bither/BitherUI.java @@ -29,6 +29,7 @@ public interface BitherUI { // Panel dimensions + int UI_MAX_WIDTH = 1100; /** * The minimum width for the application UI (900 is the minimum for tables) diff --git a/src/main/java/net/bither/db/AbstractDBHelper.java b/src/main/java/net/bither/db/AbstractDBHelper.java index 49da253..4fbd7a1 100644 --- a/src/main/java/net/bither/db/AbstractDBHelper.java +++ b/src/main/java/net/bither/db/AbstractDBHelper.java @@ -64,16 +64,21 @@ public void initDb() { int dbVersion = dbVersion(); int cuerrentVersion = currentVersion(); if (dbVersion == 0) { - onCreate(conn); + try { + onCreate(conn); + } catch (SQLException e) { + File file = new File(dbFileFullName); + if (file.exists()) { + file.delete(); + } + e.printStackTrace(); + } } else if (dbVersion() < cuerrentVersion) { onUpgrade(conn, cuerrentVersion, dbVersion); } } catch (SQLException e) { - File file = new File(dbFileFullName); - if (file.exists()) { - file.delete(); - } e.printStackTrace(); + throw new RuntimeException(e); } } diff --git a/src/main/java/net/bither/db/Address2Provider.java b/src/main/java/net/bither/db/Address2Provider.java new file mode 100644 index 0000000..0387eed --- /dev/null +++ b/src/main/java/net/bither/db/Address2Provider.java @@ -0,0 +1,125 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.db; + +import net.bither.ApplicationInstanceManager; +import net.bither.bitherj.core.Address; +import net.bither.bitherj.db.imp.AbstractAddressProvider; +import net.bither.bitherj.db.imp.base.IDb; +import net.bither.bitherj.utils.Base58; +import net.bither.bitherj.utils.Utils; +import net.bither.db.base.JavaDb; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class Address2Provider extends AbstractAddressProvider { + + private static Address2Provider addressProvider = new Address2Provider(ApplicationInstanceManager.addressDBHelper); + + public static Address2Provider getInstance() { + return addressProvider; + } + + private AddressDBHelper helper; + + public Address2Provider(AddressDBHelper helper) { + this.helper = helper; + } + + @Override + public IDb getReadDb() { + return new JavaDb(this.helper.getConn()); + } + + @Override + public IDb getWriteDb() { + return new JavaDb(this.helper.getConn()); + } + + @Override + protected int insertHDKeyToDb(IDb db, String encryptedMnemonicSeed, String encryptHdSeed, String firstAddress, boolean isXrandom) { + String insertHDSeedSql = "insert into hd_seeds (encrypt_seed,encrypt_hd_seed,is_xrandom,hdm_address) values (?,?,?,?) "; + String[] params = new String[]{encryptedMnemonicSeed, encryptHdSeed, Integer.toString(isXrandom ? 1 : 0), firstAddress}; + try { + PreparedStatement stmt = ((JavaDb) db).getConnection().prepareStatement(insertHDSeedSql); + if (params != null) { + for (int i = 0; i < params.length; i++) { + stmt.setString(i + 1, params[i]); + } + } + stmt.executeUpdate(); + ResultSet tableKeys = stmt.getGeneratedKeys(); + tableKeys.next(); + stmt.close(); + return tableKeys.getInt(1); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + protected int insertEnterpriseHDKeyToDb(IDb db, String encryptedMnemonicSeed, String encryptHdSeed, String firstAddress, boolean isXrandom) { + return 0; + } + + @Override + protected void insertHDMAddressToDb(IDb db, String address, int hdSeedId, int index, byte[] pubKeysHot, byte[] pubKeysCold, byte[] pubKeysRemote, boolean isSynced) { + String insertHDMAddressSql = "insert into hdm_addresses " + + "(hd_seed_id,hd_seed_index,pub_key_hot,pub_key_cold,pub_key_remote,address,is_synced)" + + " values (?,?,?,?,?,?,?) "; + try { + PreparedStatement stmt = ((JavaDb) db).getConnection().prepareStatement(insertHDMAddressSql); + stmt.setString(1, Integer.toString(hdSeedId)); + stmt.setString(2, Integer.toString(index)); + stmt.setString(3, Base58.encode(pubKeysHot)); + stmt.setString(4, Base58.encode(pubKeysCold)); + stmt.setString(5, pubKeysRemote == null ? null : Base58.encode(pubKeysRemote)); + stmt.setString(6, Utils.isEmpty(address) ? null : address); + stmt.setString(7, Integer.toString(isSynced ? 1 : 0)); + stmt.executeUpdate(); + stmt.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + protected void insertAddressToDb(IDb db, Address address) { + String insertAddressSql = "insert into addresses " + + "(address,encrypt_private_key,pub_key,is_xrandom,is_trash,is_synced,sort_time)" + + " values (?,?,?,?,?,?,?) "; + String[] params = new String[]{address.getAddress(), address.hasPrivKey() ? address.getEncryptPrivKeyOfDb() : null, Base58.encode(address.getPubKey()), + Integer.toString(address.isFromXRandom() ? 1 : 0), Integer.toString(address.isTrashed() ? 1 : 0), Integer.toString(address.isSyncComplete() ? 1 : 0), Long.toString(address.getSortTime())}; + try { + PreparedStatement stmt = ((JavaDb) db).getConnection().prepareStatement(insertAddressSql); + if (params != null) { + for (int i = 0; i < params.length; i++) { + stmt.setString(i + 1, params[i]); + } + } + stmt.executeUpdate(); + stmt.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/net/bither/db/AddressDBHelper.java b/src/main/java/net/bither/db/AddressDBHelper.java index 2fd4445..3c3a27a 100644 --- a/src/main/java/net/bither/db/AddressDBHelper.java +++ b/src/main/java/net/bither/db/AddressDBHelper.java @@ -28,13 +28,23 @@ public class AddressDBHelper extends AbstractDBHelper { + public static final String CREATE_ENTERPRISE_HDM_ACCOUNT = "create table if not exists enterprise_hdm_account " + + "( hd_account_id integer not null primary key autoincrement" + + ", encrypt_seed text " + + ", encrypt_mnemonic_seed text" + + ", hd_address text " + + ", external_pub text not null" + + ", internal_pub text not null" + + ", is_xrandom integer);"; + private static final String DB_NAME = "address.db"; - private static final int CURRENT_VERSION = 3; + private static final int CURRENT_VERSION = 4; public AddressDBHelper(String dbDir) { super(dbDir); } + @Override protected String getDBName() { return DB_NAME; @@ -71,6 +81,8 @@ protected void onUpgrade(Connection conn, int newVersion, int oldVerion) throws v1Tov2(stmt); case 2: v2ToV3(stmt); + case 3: + v3Tov4(stmt); } conn.commit(); @@ -93,6 +105,8 @@ protected void onCreate(Connection conn) throws SQLException { stmt.executeUpdate(AbstractDb.CREATE_ALIASES_SQL); stmt.executeUpdate(AbstractDb.CREATE_VANITY_ADDRESS_SQL); stmt.executeUpdate(AbstractDb.CREATE_HD_ACCOUNT); + + stmt.executeUpdate(CREATE_ENTERPRISE_HDM_ACCOUNT); conn.commit(); stmt.close(); UserPreference.getInstance().setAddressDbVersion(CURRENT_VERSION); @@ -110,6 +124,44 @@ private void v2ToV3(Statement statement) throws SQLException { statement.executeUpdate(AbstractDb.CREATE_VANITY_ADDRESS_SQL); } + //1.3.6 + private void v3Tov4(Statement statement) throws SQLException { + + statement.executeUpdate(CREATE_ENTERPRISE_HDM_ACCOUNT); + + // modify encrypt_seed null + statement.executeUpdate("create table if not exists hd_account2 " + + "( hd_account_id integer not null primary key autoincrement" + + ", encrypt_seed text" + + ", encrypt_mnemonic_seed text" + + ", hd_address text not null" + + ", external_pub text not null" + + ", internal_pub text not null" + + ", is_xrandom integer not null);"); + statement.executeUpdate("INSERT INTO hd_account2(hd_account_id,encrypt_seed,encrypt_mnemonic_seed,hd_address,external_pub,internal_pub,is_xrandom) " + + " SELECT hd_account_id,encrypt_seed,encrypt_mnemonic_seed,hd_address,external_pub,internal_pub,is_xrandom FROM hd_account;"); + int oldCnt = 0; + int newCnt = 0; + ResultSet c = statement.executeQuery("select count(0) cnt from hd_account"); + if (c.next()) { + oldCnt = c.getInt(0); + } + c.close(); + c = statement.executeQuery("select count(0) cnt from hd_account2"); + if (c.next()) { + newCnt = c.getInt(0); + } + c.close(); + if (oldCnt != newCnt) { + throw new RuntimeException("address db upgrade from 6 to 7 failed. new hd_account_addresses table record count not the same as old one"); + } else { + statement.executeUpdate("DROP TABLE hd_account;"); + statement.executeUpdate("ALTER TABLE hd_account2 RENAME TO hd_account;"); + } + + } + + private boolean hasAddressTables(Connection conn) throws SQLException { ResultSet rs = conn.getMetaData().getTables(null, null, AbstractDb.Tables.Addresses, null); boolean hasTable = rs.next(); diff --git a/src/main/java/net/bither/db/AddressProvider.java b/src/main/java/net/bither/db/AddressProvider.java index 9d053a7..ac98a95 100644 --- a/src/main/java/net/bither/db/AddressProvider.java +++ b/src/main/java/net/bither/db/AddressProvider.java @@ -83,9 +83,13 @@ public boolean changePassword(CharSequence oldPassword, CharSequence newPassword HashMap hdEncryptSeedHashMap = new HashMap(); HashMap hdEncryptMnemonicSeedHashMap = new HashMap(); + HashMap singularModeBackupHashMap = new HashMap(); + + + HashMap desktopHdmEncryptSeedHashMap = new HashMap(); + HashMap desktopHdEmncryptMnemonicSeedHashMap = new HashMap(); - HashMap singularModeBackupHashMap = new HashMap(); try { String sql = "select address,encrypt_private_key,pub_key,is_xrandom from addresses where encrypt_private_key is not null"; PreparedStatement statement = this.mDb.getPreparedStatement(sql, null); @@ -190,6 +194,31 @@ public boolean changePassword(CharSequence oldPassword, CharSequence newPassword c.close(); statement.close(); + + statement = this.mDb.getPreparedStatement("select hd_account_id,encrypt_seed,encrypt_mnemonic_seed from enterprise_hdm_account " + + " where encrypt_seed is not null and encrypt_mnemonic_seed is not null ", null); + c = statement.executeQuery(); + while (c.next()) { + int idColumn = c.findColumn("hd_account_id"); + Integer hdAccountId = 0; + if (idColumn != -1) { + hdAccountId = c.getInt(idColumn); + } + idColumn = c.findColumn("encrypt_seed"); + if (idColumn != -1) { + String encryptSeed = c.getString(idColumn); + desktopHdmEncryptSeedHashMap.put(hdAccountId, encryptSeed); + } + idColumn = c.findColumn("encrypt_mnemonic_seed"); + if (idColumn != -1) { + String encryptHDSeed = c.getString(idColumn); + desktopHdEmncryptMnemonicSeedHashMap.put(hdAccountId, encryptHDSeed); + } + + } + c.close(); + statement.close(); + sql = "select password_seed from password_seed limit 1"; statement = this.mDb.getPreparedStatement(sql, null); c = statement.executeQuery(); @@ -229,6 +258,15 @@ public boolean changePassword(CharSequence oldPassword, CharSequence newPassword for (Map.Entry kv : hdEncryptMnemonicSeedHashMap.entrySet()) { kv.setValue(EncryptedData.changePwd(kv.getValue(), oldPassword, newPassword)); } + + + for (Map.Entry kv : desktopHdmEncryptSeedHashMap.entrySet()) { + kv.setValue(EncryptedData.changePwd(kv.getValue(), oldPassword, newPassword)); + } + for (Map.Entry kv : desktopHdEmncryptMnemonicSeedHashMap.entrySet()) { + kv.setValue(EncryptedData.changePwd(kv.getValue(), oldPassword, newPassword)); + } + if (passwordSeed != null) { boolean result = passwordSeed.changePassword(oldPassword, newPassword); if (!result) { @@ -286,6 +324,20 @@ public boolean changePassword(CharSequence oldPassword, CharSequence newPassword stmt.executeUpdate(); stmt.close(); } + + + sql = "update enterprise_hdm_account set encrypt_seed=?,encrypt_mnemonic_seed=? where hd_account_id=? "; + + for (Map.Entry kv : desktopHdmEncryptSeedHashMap.entrySet()) { + + PreparedStatement stmt = this.mDb.getConn().prepareStatement(sql); + stmt.setString(1, kv.getValue()); + stmt.setString(2, desktopHdEmncryptMnemonicSeedHashMap.get(kv.getKey())); + stmt.setString(3, kv.getKey().toString()); + stmt.executeUpdate(); + stmt.close(); + } + if (finalPasswordSeed != null) { sql = "update password_seed set password_seed=? "; PreparedStatement stmt = this.mDb.getConn().prepareStatement(sql); @@ -327,7 +379,7 @@ public PasswordSeed getPasswordSeed() { public boolean hasPasswordSeed() { boolean result = false; try { - result = hasPasswordSeed(this.mDb.getConn()); + result = AddressProvider.hasPasswordSeed(this.mDb.getConn()); } catch (SQLException e) { e.printStackTrace(); } @@ -335,7 +387,7 @@ public boolean hasPasswordSeed() { } - private boolean hasPasswordSeed(Connection conn) throws SQLException { + public static boolean hasPasswordSeed(Connection conn) throws SQLException { PreparedStatement stmt = conn.prepareStatement("select count(0) cnt from password_seed where password_seed is not null "); ResultSet c = stmt.executeQuery(); int count = 0; @@ -487,8 +539,8 @@ public int addHDKey(final String encryptedMnemonicSeed, final String encryptHdSe } stmt.executeUpdate(); stmt.close(); - if (!hasPasswordSeed(this.mDb.getConn()) && !Utils.isEmpty(addressOfPS)) { - addPasswordSeed(this.mDb.getConn(), new PasswordSeed(addressOfPS, encryptedMnemonicSeed)); + if (!AddressProvider.hasPasswordSeed(this.mDb.getConn()) && !Utils.isEmpty(addressOfPS)) { + AddressProvider.addPasswordSeed(this.mDb.getConn(), new PasswordSeed(addressOfPS, encryptedMnemonicSeed)); } this.mDb.getConn().commit(); PreparedStatement statement = this.mDb.getPreparedStatement("select hd_seed_id from hd_seeds where encrypt_seed=? and encrypt_hd_seed=? and is_xrandom=? and hdm_address=?" @@ -510,6 +562,11 @@ public int addHDKey(final String encryptedMnemonicSeed, final String encryptHdSe return result; } + @Override + public int addEnterpriseHDKey(String encryptedMnemonicSeed, String encryptHdSeed, String firstAddress, boolean isXrandom, String addressOfPS) { + return 0; + } + @Override public HDMBId getHDMBId() { HDMBId hdmbId = null; @@ -572,8 +629,8 @@ public void addAndUpdateHDMBId(final HDMBId bitherId, final String addressOfPS) stmt.setString(1, bitherId.getAddress()); stmt.setString(2, encryptedBitherPasswordString); stmt.executeUpdate(); - if (!hasPasswordSeed(this.mDb.getConn()) && !Utils.isEmpty(addressOfPS)) { - addPasswordSeed(this.mDb.getConn(), new PasswordSeed(addressOfPS, encryptedBitherPasswordString)); + if (!AddressProvider.hasPasswordSeed(this.mDb.getConn()) && !Utils.isEmpty(addressOfPS)) { + AddressProvider.addPasswordSeed(this.mDb.getConn(), new PasswordSeed(addressOfPS, encryptedBitherPasswordString)); } this.mDb.getConn().commit(); stmt.close(); @@ -588,8 +645,8 @@ public void addAndUpdateHDMBId(final HDMBId bitherId, final String addressOfPS) stmt.setString(1, encryptedBitherPasswordString); stmt.setString(2, bitherId.getAddress()); stmt.executeUpdate(); - if (!hasPasswordSeed(this.mDb.getConn()) && !Utils.isEmpty(addressOfPS)) { - addPasswordSeed(this.mDb.getConn(), new PasswordSeed(addressOfPS, encryptedBitherPasswordString)); + if (!AddressProvider.hasPasswordSeed(this.mDb.getConn()) && !Utils.isEmpty(addressOfPS)) { + AddressProvider.addPasswordSeed(this.mDb.getConn(), new PasswordSeed(addressOfPS, encryptedBitherPasswordString)); } this.mDb.getConn().commit(); stmt.close(); @@ -922,7 +979,7 @@ public void addAddress(final Address address) { this.mDb.getConn().setAutoCommit(false); String[] params = new String[]{address.getAddress(), address.hasPrivKey() ? address.getEncryptPrivKeyOfDb() : null, Base58.encode(address.getPubKey()), - Integer.toString(address.isFromXRandom() ? 1 : 0), Integer.toString(address.isSyncComplete() ? 1 : 0), Integer.toString(address.isTrashed() ? 1 : 0), Long.toString(address.getSortTime())}; + Integer.toString(address.isFromXRandom() ? 1 : 0), Integer.toString(address.isTrashed() ? 1 : 0), Integer.toString(address.isSyncComplete() ? 1 : 0), Long.toString(address.getSortTime())}; PreparedStatement stmt = this.mDb.getConn().prepareStatement(insertAddressSql); if (params != null) { for (int i = 0; i < params.length; i++) { @@ -931,9 +988,9 @@ public void addAddress(final Address address) { } stmt.executeUpdate(); if (address.hasPrivKey()) { - if (!hasPasswordSeed(this.mDb.getConn())) { + if (!AddressProvider.hasPasswordSeed(this.mDb.getConn())) { PasswordSeed passwordSeed = new PasswordSeed(address.getAddress(), address.getFullEncryptPrivKeyOfDb()); - addPasswordSeed(this.mDb.getConn(), passwordSeed); + AddressProvider.addPasswordSeed(this.mDb.getConn(), passwordSeed); } } this.mDb.getConn().commit(); @@ -1136,214 +1193,214 @@ public String getSingularModeBackup(int hdSeedId) { } - @Override - public int addHDAccount(String encryptedMnemonicSeed, String encryptSeed, - String firstAddress, boolean isXrandom, String addressOfPS, - byte[] externalPub, byte[] internalPub) { - int result = 0; - try { - - String[] params = new String[]{encryptedMnemonicSeed, encryptSeed, firstAddress, Base58.encode(externalPub) - , Base58.encode(internalPub), Integer.toString(isXrandom ? 1 : 0),}; - String sql = "insert into hd_account(encrypt_mnemonic_seed,encrypt_seed" + - ",hd_address,external_pub,internal_pub,is_xrandom) " + - " values(?,?,?,?,?,?)"; - - this.mDb.getConn().setAutoCommit(false); - - PreparedStatement stmt = this.mDb.getConn().prepareStatement(sql); - if (params != null) { - for (int i = 0; i < params.length; i++) { - stmt.setString(i + 1, params[i]); - } - } - stmt.executeUpdate(); - stmt.close(); - if (!hasPasswordSeed(this.mDb.getConn()) && !Utils.isEmpty(addressOfPS)) { - addPasswordSeed(this.mDb.getConn(), new PasswordSeed(addressOfPS, encryptedMnemonicSeed)); - } - this.mDb.getConn().commit(); - stmt = this.mDb.getPreparedStatement("select hd_account_id from hd_account where encrypt_mnemonic_seed=? and encrypt_seed=? and is_xrandom=? and hd_address=?" - , new String[]{encryptedMnemonicSeed, encryptSeed, Integer.toString(isXrandom ? 1 : 0), firstAddress}); - ResultSet cursor = stmt.executeQuery(); - if (cursor.next()) { - int idColumn = cursor.findColumn(AbstractDb.HDAccountColumns.HD_ACCOUNT_ID); - if (idColumn != -1) { - result = cursor.getInt(idColumn); - } - - } - cursor.close(); - stmt.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return result; - - } - - @Override - public String getHDFristAddress(int hdSeedId) { - String address = null; - try { - PreparedStatement statement = this.mDb.getPreparedStatement("select hd_address from hd_account where hd_account_id=?" - , new String[]{Integer.toString(hdSeedId)}); - ResultSet cursor = statement.executeQuery(); - if (cursor.next()) { - int idColumn = cursor.findColumn(AbstractDb.HDAccountColumns.HD_ADDRESS); - if (idColumn != -1) { - address = cursor.getString(idColumn); - } - } - cursor.close(); - statement.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return address; - } - - @Override - public byte[] getExternalPub(int hdSeedId) { - byte[] pub = null; - try { - PreparedStatement statement = this.mDb.getPreparedStatement("select external_pub from hd_account where hd_account_id=? " - , new String[]{Integer.toString(hdSeedId)}); - ResultSet c = statement.executeQuery(); - if (c.next()) { - int idColumn = c.findColumn(AbstractDb.HDAccountColumns.EXTERNAL_PUB); - if (idColumn != -1) { - String pubStr = c.getString(idColumn); - pub = Base58.decode(pubStr); - } - } - c.close(); - statement.close(); - } catch (AddressFormatException e) { - e.printStackTrace(); - } catch (SQLException e) { - e.printStackTrace(); - } - - return pub; - } - - @Override - public byte[] getInternalPub(int hdSeedId) { - byte[] pub = null; - try { - PreparedStatement statement = this.mDb.getPreparedStatement("select internal_pub from hd_account where hd_account_id=? " - , new String[]{Integer.toString(hdSeedId)}); - ResultSet c = statement.executeQuery(); - if (c.next()) { - int idColumn = c.findColumn(AbstractDb.HDAccountColumns.INTERNAL_PUB); - if (idColumn != -1) { - String pubStr = c.getString(idColumn); - pub = Base58.decode(pubStr); - } - } - c.close(); - statement.close(); - } catch (AddressFormatException e) { - e.printStackTrace(); - } catch (SQLException e) { - e.printStackTrace(); - } - - return pub; - } - - @Override - public String getHDAccountEncryptSeed(int hdSeedId) { - String hdAccountEncryptSeed = null; - try { - PreparedStatement statement = this.mDb.getPreparedStatement("select " + AbstractDb.HDAccountColumns.ENCRYPT_SEED + " from hd_account where hd_account_id=? " - , new String[]{Integer.toString(hdSeedId)}); - ResultSet c = statement.executeQuery(); - if (c.next()) { - int idColumn = c.findColumn(AbstractDb.HDAccountColumns.ENCRYPT_SEED); - if (idColumn != -1) { - hdAccountEncryptSeed = c.getString(idColumn); - } - } - c.close(); - statement.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return hdAccountEncryptSeed; - - } - - @Override - public String getHDAccountEncryptMnmonicSeed(int hdSeedId) { - String hdAccountMnmonicEncryptSeed = null; - try { - PreparedStatement statement = this.mDb.getPreparedStatement("select " + AbstractDb.HDAccountColumns.ENCRYPT_MNMONIC_SEED + " from hd_account where hd_account_id=? " - , new String[]{Integer.toString(hdSeedId)}); - ResultSet c = statement.executeQuery(); - if (c.next()) { - int idColumn = c.findColumn(AbstractDb.HDAccountColumns.ENCRYPT_MNMONIC_SEED); - if (idColumn != -1) { - hdAccountMnmonicEncryptSeed = c.getString(idColumn); - } - } - c.close(); - statement.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return hdAccountMnmonicEncryptSeed; - - - } - - @Override - public List getHDAccountSeeds() { - List hdSeedIds = new ArrayList(); - - try { - - String sql = "select " + AbstractDb.HDAccountColumns.HD_ACCOUNT_ID + " from " + AbstractDb.Tables.HD_ACCOUNT; - PreparedStatement statement = this.mDb.getPreparedStatement(sql, null); - ResultSet c = statement.executeQuery(); - while (c.next()) { - int idColumn = c.findColumn(AbstractDb.HDAccountColumns.HD_ACCOUNT_ID); - if (idColumn != -1) { - hdSeedIds.add(c.getInt(idColumn)); - } - } - c.close(); - statement.close(); - } catch (Exception ex) { - ex.printStackTrace(); - } - return hdSeedIds; - } - - @Override - public boolean hdAccountIsXRandom(int seedId) { - boolean result = false; - String sql = "select is_xrandom from hd_account where hd_account_id=?"; - try { - PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Integer.toString(seedId)}); - ResultSet rs = statement.executeQuery(); - if (rs.next()) { - int idColumn = rs.findColumn(AbstractDb.HDAccountColumns.IS_XRANDOM); - if (idColumn != -1) { - result = rs.getBoolean(idColumn); - } - } - rs.close(); - statement.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - - return result; - } - - public void addPasswordSeed(Connection conn, PasswordSeed passwordSeed) throws SQLException { +// @Override +// public int addHDAccount(String encryptedMnemonicSeed, String encryptSeed, +// String firstAddress, boolean isXrandom, String addressOfPS, +// byte[] externalPub, byte[] internalPub) { +// int result = 0; +// try { +// +// String[] params = new String[]{encryptedMnemonicSeed, encryptSeed, firstAddress, Base58.encode(externalPub) +// , Base58.encode(internalPub), Integer.toString(isXrandom ? 1 : 0),}; +// String sql = "insert into hd_account(encrypt_mnemonic_seed,encrypt_seed" + +// ",hd_address,external_pub,internal_pub,is_xrandom) " + +// " values(?,?,?,?,?,?)"; +// +// this.mDb.getConn().setAutoCommit(false); +// +// PreparedStatement stmt = this.mDb.getConn().prepareStatement(sql); +// if (params != null) { +// for (int i = 0; i < params.length; i++) { +// stmt.setString(i + 1, params[i]); +// } +// } +// stmt.executeUpdate(); +// stmt.close(); +// if (!hasPasswordSeed(this.mDb.getConn()) && !Utils.isEmpty(addressOfPS)) { +// addPasswordSeed(this.mDb.getConn(), new PasswordSeed(addressOfPS, encryptedMnemonicSeed)); +// } +// this.mDb.getConn().commit(); +// stmt = this.mDb.getPreparedStatement("select hd_account_id from hd_account where encrypt_mnemonic_seed=? and encrypt_seed=? and is_xrandom=? and hd_address=?" +// , new String[]{encryptedMnemonicSeed, encryptSeed, Integer.toString(isXrandom ? 1 : 0), firstAddress}); +// ResultSet cursor = stmt.executeQuery(); +// if (cursor.next()) { +// int idColumn = cursor.findColumn(AbstractDb.HDAccountColumns.HD_ACCOUNT_ID); +// if (idColumn != -1) { +// result = cursor.getInt(idColumn); +// } +// +// } +// cursor.close(); +// stmt.close(); +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// return result; +// +// } +// +// @Override +// public String getHDFristAddress(int hdSeedId) { +// String address = null; +// try { +// PreparedStatement statement = this.mDb.getPreparedStatement("select hd_address from hd_account where hd_account_id=?" +// , new String[]{Integer.toString(hdSeedId)}); +// ResultSet cursor = statement.executeQuery(); +// if (cursor.next()) { +// int idColumn = cursor.findColumn(AbstractDb.HDAccountColumns.HD_ADDRESS); +// if (idColumn != -1) { +// address = cursor.getString(idColumn); +// } +// } +// cursor.close(); +// statement.close(); +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// return address; +// } +// +// @Override +// public byte[] getExternalPub(int hdSeedId) { +// byte[] pub = null; +// try { +// PreparedStatement statement = this.mDb.getPreparedStatement("select external_pub from hd_account where hd_account_id=? " +// , new String[]{Integer.toString(hdSeedId)}); +// ResultSet c = statement.executeQuery(); +// if (c.next()) { +// int idColumn = c.findColumn(AbstractDb.HDAccountColumns.EXTERNAL_PUB); +// if (idColumn != -1) { +// String pubStr = c.getString(idColumn); +// pub = Base58.decode(pubStr); +// } +// } +// c.close(); +// statement.close(); +// } catch (AddressFormatException e) { +// e.printStackTrace(); +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// +// return pub; +// } +// +// @Override +// public byte[] getInternalPub(int hdSeedId) { +// byte[] pub = null; +// try { +// PreparedStatement statement = this.mDb.getPreparedStatement("select internal_pub from hd_account where hd_account_id=? " +// , new String[]{Integer.toString(hdSeedId)}); +// ResultSet c = statement.executeQuery(); +// if (c.next()) { +// int idColumn = c.findColumn(AbstractDb.HDAccountColumns.INTERNAL_PUB); +// if (idColumn != -1) { +// String pubStr = c.getString(idColumn); +// pub = Base58.decode(pubStr); +// } +// } +// c.close(); +// statement.close(); +// } catch (AddressFormatException e) { +// e.printStackTrace(); +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// +// return pub; +// } +// +// @Override +// public String getHDAccountEncryptSeed(int hdSeedId) { +// String hdAccountEncryptSeed = null; +// try { +// PreparedStatement statement = this.mDb.getPreparedStatement("select " + AbstractDb.HDAccountColumns.ENCRYPT_SEED + " from hd_account where hd_account_id=? " +// , new String[]{Integer.toString(hdSeedId)}); +// ResultSet c = statement.executeQuery(); +// if (c.next()) { +// int idColumn = c.findColumn(AbstractDb.HDAccountColumns.ENCRYPT_SEED); +// if (idColumn != -1) { +// hdAccountEncryptSeed = c.getString(idColumn); +// } +// } +// c.close(); +// statement.close(); +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// return hdAccountEncryptSeed; +// +// } +// +// @Override +// public String getHDAccountEncryptMnmonicSeed(int hdSeedId) { +// String hdAccountMnmonicEncryptSeed = null; +// try { +// PreparedStatement statement = this.mDb.getPreparedStatement("select " + AbstractDb.HDAccountColumns.ENCRYPT_MNMONIC_SEED + " from hd_account where hd_account_id=? " +// , new String[]{Integer.toString(hdSeedId)}); +// ResultSet c = statement.executeQuery(); +// if (c.next()) { +// int idColumn = c.findColumn(AbstractDb.HDAccountColumns.ENCRYPT_MNMONIC_SEED); +// if (idColumn != -1) { +// hdAccountMnmonicEncryptSeed = c.getString(idColumn); +// } +// } +// c.close(); +// statement.close(); +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// return hdAccountMnmonicEncryptSeed; +// +// +// } +// +// @Override +// public List getHDAccountSeeds() { +// List hdSeedIds = new ArrayList(); +// +// try { +// +// String sql = "select " + AbstractDb.HDAccountColumns.HD_ACCOUNT_ID + " from " + AbstractDb.Tables.HD_ACCOUNT; +// PreparedStatement statement = this.mDb.getPreparedStatement(sql, null); +// ResultSet c = statement.executeQuery(); +// while (c.next()) { +// int idColumn = c.findColumn(AbstractDb.HDAccountColumns.HD_ACCOUNT_ID); +// if (idColumn != -1) { +// hdSeedIds.add(c.getInt(idColumn)); +// } +// } +// c.close(); +// statement.close(); +// } catch (Exception ex) { +// ex.printStackTrace(); +// } +// return hdSeedIds; +// } +// +// @Override +// public boolean hdAccountIsXRandom(int seedId) { +// boolean result = false; +// String sql = "select is_xrandom from hd_account where hd_account_id=?"; +// try { +// PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Integer.toString(seedId)}); +// ResultSet rs = statement.executeQuery(); +// if (rs.next()) { +// int idColumn = rs.findColumn(AbstractDb.HDAccountColumns.IS_XRANDOM); +// if (idColumn != -1) { +// result = rs.getBoolean(idColumn); +// } +// } +// rs.close(); +// statement.close(); +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// +// return result; +// } + + public static void addPasswordSeed(Connection conn, PasswordSeed passwordSeed) throws SQLException { PreparedStatement stmt = conn.prepareStatement("insert into password_seed (password_seed) values (?)"); stmt.setString(1, passwordSeed.toPasswordSeedString()); stmt.executeUpdate(); diff --git a/src/main/java/net/bither/db/Block2Provider.java b/src/main/java/net/bither/db/Block2Provider.java new file mode 100644 index 0000000..751e2d2 --- /dev/null +++ b/src/main/java/net/bither/db/Block2Provider.java @@ -0,0 +1,49 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.db; + +import net.bither.ApplicationInstanceManager; +import net.bither.bitherj.db.imp.AbstractBlockProvider; +import net.bither.bitherj.db.imp.base.IDb; +import net.bither.db.base.JavaDb; + +public class Block2Provider extends AbstractBlockProvider { + + private static Block2Provider blockProvider = new Block2Provider(ApplicationInstanceManager.txDBHelper); + + public static Block2Provider getInstance() { + return blockProvider; + } + + private TxDBHelper helper; + + public Block2Provider(TxDBHelper helper) { + this.helper = helper; + } + + @Override + public IDb getReadDb() { + return new JavaDb(this.helper.getConn()); + } + + @Override + public IDb getWriteDb() { + return new JavaDb(this.helper.getConn()); + } +} diff --git a/src/main/java/net/bither/db/BlockProvider.java b/src/main/java/net/bither/db/BlockProvider.java index 06b1a05..ce78f61 100644 --- a/src/main/java/net/bither/db/BlockProvider.java +++ b/src/main/java/net/bither/db/BlockProvider.java @@ -270,13 +270,11 @@ public boolean isExist(byte[] blockHash) { public void addBlocks(List blockItemList) { final List addBlockList = new ArrayList(); - List allBlockList = getAllBlocks(); for (Block item : blockItemList) { - if (!allBlockList.contains(item)) { + if (!this.blockExists(item.getBlockHash())) { addBlockList.add(item); } } - allBlockList.clear(); try { this.mDb.getConn().setAutoCommit(false); for (Block item : addBlockList) { diff --git a/src/main/java/net/bither/db/DesktopAddressProvider.java b/src/main/java/net/bither/db/DesktopAddressProvider.java new file mode 100644 index 0000000..d867cb1 --- /dev/null +++ b/src/main/java/net/bither/db/DesktopAddressProvider.java @@ -0,0 +1,264 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.db; + +import net.bither.ApplicationInstanceManager; +import net.bither.bitherj.crypto.PasswordSeed; +import net.bither.bitherj.db.AbstractDb; +import net.bither.bitherj.db.IDesktopAddressProvider; +import net.bither.bitherj.exception.AddressFormatException; +import net.bither.bitherj.utils.Base58; +import net.bither.bitherj.utils.Utils; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class DesktopAddressProvider implements IDesktopAddressProvider { + + private static final String insert_hd_seed_sql = "insert into enterprise_hdm_account " + + "(encrypt_mnemonic_seed,encrypt_seed,is_xrandom,hd_address,external_pub,internal_pub)" + + " values (?,?,?,?,?,?) "; + + private static DesktopAddressProvider addressProvider = + new DesktopAddressProvider(ApplicationInstanceManager.addressDBHelper); + + public static DesktopAddressProvider getInstance() { + return addressProvider; + } + + private DesktopAddressProvider(AddressDBHelper db) { + this.mDb = db; + } + + private AddressDBHelper mDb; + + public int addHDKey(String encryptedMnemonicSeed, String encryptHdSeed, + String firstAddress, boolean isXrandom, String addressOfPS + , byte[] externalPub, byte[] internalPub) { + int result = 0; + try { + this.mDb.getConn().setAutoCommit(false); + String[] params = new String[]{encryptedMnemonicSeed, encryptHdSeed, Integer.toString(isXrandom ? 1 : 0), firstAddress, + Base58.encode(externalPub), Base58.encode(internalPub)}; + PreparedStatement stmt = this.mDb.getConn().prepareStatement(insert_hd_seed_sql); + if (params != null) { + for (int i = 0; i < params.length; i++) { + stmt.setString(i + 1, params[i]); + } + } + stmt.executeUpdate(); + stmt.close(); + if (!AddressProvider.getInstance().hasPasswordSeed(this.mDb.getConn()) && !Utils.isEmpty(addressOfPS)) { + AddressProvider.getInstance().addPasswordSeed(this.mDb.getConn(), new PasswordSeed(addressOfPS, encryptedMnemonicSeed)); + } + this.mDb.getConn().commit(); + PreparedStatement statement = this.mDb.getPreparedStatement("select hd_account_id from enterprise_hdm_account where hd_address=?" + , new String[]{firstAddress}); + ResultSet cursor = statement.executeQuery(); + + if (cursor.next()) { + int idColumn = cursor.findColumn("hd_account_id"); + if (idColumn != -1) { + result = cursor.getInt(idColumn); + } + + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return result; + } + + public void addHDMPub(List externalPubs, List internalPubs) { + try { + String hdSeedSql = "insert into enterprise_hdm_account " + + "(external_pub,internal_pub)" + + " values (?,?)"; + this.mDb.getConn().setAutoCommit(false); + for (int i = 0; i < externalPubs.size(); i++) { + PreparedStatement statement = this.mDb.getPreparedStatement(hdSeedSql, new String[]{ + Base58.encode(externalPubs.get(i)), Base58.encode(internalPubs.get(i)) + }); + statement.executeUpdate(); + statement.close(); + } + this.mDb.getConn().commit(); + + } catch (SQLException e) { + e.printStackTrace(); + } + + } + + public List getExternalPubs() { + + List externalPubs = new ArrayList(); + try { + String sql = "select external_pub from enterprise_hdm_account order by hd_account_id asc"; + PreparedStatement stmt = this.mDb.getConn().prepareStatement(sql); + ResultSet cursor = stmt.executeQuery(); + while (cursor.next()) { + int idColumn = cursor.findColumn("external_pub"); + if (idColumn != -1) { + String str = cursor.getString(idColumn); + externalPubs.add(Base58.decode(str)); + } + } + } catch (SQLException e) { + e.printStackTrace(); + } catch (AddressFormatException e) { + e.printStackTrace(); + } + return externalPubs; + + } + + public List getInternalPubs() { + List internalPubs = new ArrayList(); + try { + String sql = "select internal_pub from enterprise_hdm_account order by hd_account_id asc"; + PreparedStatement stmt = this.mDb.getConn().prepareStatement(sql); + ResultSet cursor = stmt.executeQuery(); + while (cursor.next()) { + int idColumn = cursor.findColumn("internal_pub"); + if (idColumn != -1) { + String str = cursor.getString(idColumn); + internalPubs.add(Base58.decode(str)); + } + } + } catch (SQLException e) { + e.printStackTrace(); + } catch (AddressFormatException e) { + e.printStackTrace(); + } + return internalPubs; + + } + + public boolean isHDSeedFromXRandom(int hdSeedId) { + boolean isXRandom = false; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select is_xrandom from enterprise_hdm_account where hd_account_id=? " + , new String[]{Integer.toString(hdSeedId)}); + ResultSet cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn("is_xrandom"); + if (idColumn != -1) { + isXRandom = cursor.getInt(idColumn) == 1; + } + } + cursor.close(); + statement.close(); + } catch (SQLException ex) { + ex.printStackTrace(); + } + return isXRandom; + + } + + + public String getEncryptMnemonicSeed(int hdSeedId) { + String encryptMnemonicSeed = null; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select encrypt_mnemonic_seed from enterprise_hdm_account where hd_account_id=? " + , new String[]{Integer.toString(hdSeedId)}); + ResultSet cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn("encrypt_mnemonic_seed"); + if (idColumn != -1) { + encryptMnemonicSeed = cursor.getString(idColumn); + } + } + cursor.close(); + statement.close(); + } catch (SQLException ex) { + ex.printStackTrace(); + } + return encryptMnemonicSeed; + } + + public String getEncryptHDSeed(int hdSeedId) { + String encryptSeed = null; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select encrypt_seed from enterprise_hdm_account where hd_account_id=? " + , new String[]{Integer.toString(hdSeedId)}); + ResultSet cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn("encrypt_seed"); + if (idColumn != -1) { + encryptSeed = cursor.getString(idColumn); + } + } + cursor.close(); + statement.close(); + } catch (SQLException ex) { + ex.printStackTrace(); + } + return encryptSeed; + } + + public String getHDMFristAddress(int hdSeedId) { + String address = null; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select hd_address from enterprise_hdm_account where hd_account_id=? " + , new String[]{Integer.toString(hdSeedId)}); + ResultSet cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn("hd_address"); + if (idColumn != -1) { + address = cursor.getString(idColumn); + } + } + cursor.close(); + statement.close(); + } catch (SQLException ex) { + ex.printStackTrace(); + } + return address; + } + + @Override + public List getDesktopKeyChainSeed() { + List seeds = new ArrayList(); + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select hd_account_id from enterprise_hdm_account where encrypt_seed is not null order by hd_account_id asc " + , null); + + ResultSet cursor = statement.executeQuery(); + while (cursor.next()) { + int idColumn = cursor.findColumn("hd_account_id"); + if (idColumn != -1) { + seeds.add(cursor.getInt(idColumn)); + } + } + cursor.close(); + statement.close(); + } catch (SQLException ex) { + ex.printStackTrace(); + } + return seeds; + } + + +} diff --git a/src/main/java/net/bither/db/DesktopDbImpl.java b/src/main/java/net/bither/db/DesktopDbImpl.java index deaa5f5..dbf9b89 100644 --- a/src/main/java/net/bither/db/DesktopDbImpl.java +++ b/src/main/java/net/bither/db/DesktopDbImpl.java @@ -21,26 +21,46 @@ public class DesktopDbImpl extends AbstractDb { @Override public IBlockProvider initBlockProvider() { - return BlockProvider.getInstance(); + return Block2Provider.getInstance(); } @Override public IPeerProvider initPeerProvider() { - return PeerProvider.getInstance(); + return Peer2Provider.getInstance(); } @Override public ITxProvider initTxProvider() { - return TxProvider.getInstance(); + return Tx2Provider.getInstance(); } @Override public IAddressProvider initAddressProvider() { - return AddressProvider.getInstance(); + return Address2Provider.getInstance(); + } + + @Override + public IHDAccountAddressProvider initHDAccountAddressProvider() { + return HDAccountAddress2Provider.getInstance(); } @Override public IHDAccountProvider initHDAccountProvider() { - return HDAccountProvider.getInstance(); + return HDAccount2Provider.getInstance(); + } + + @Override + public EnterpriseHDMProvider initEnterpriseHDMProvider() { + return EnterpriseHDMProvider.getInstance(); + } + + @Override + public IDesktopAddressProvider initEnDesktopAddressProvider() { + return DesktopAddressProvider.getInstance(); + } + + @Override + public IDesktopTxProvider initDesktopTxProvider() { + return DesktopTxProvider.getInstance(); } } diff --git a/src/main/java/net/bither/db/DesktopTxProvider.java b/src/main/java/net/bither/db/DesktopTxProvider.java new file mode 100644 index 0000000..225ab0a --- /dev/null +++ b/src/main/java/net/bither/db/DesktopTxProvider.java @@ -0,0 +1,632 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.db; + +import net.bither.ApplicationInstanceManager; +import net.bither.bitherj.core.*; +import net.bither.bitherj.db.AbstractDb; +import net.bither.bitherj.db.IDesktopTxProvider; +import net.bither.bitherj.exception.AddressFormatException; +import net.bither.bitherj.utils.Base58; +import net.bither.bitherj.utils.Sha256Hash; +import net.bither.bitherj.utils.Utils; +import net.bither.utils.SystemUtil; + + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +public class DesktopTxProvider implements IDesktopTxProvider { + + private final static String queryTxHashOfHDAccount = " select distinct txs.tx_hash from addresses_txs txs ,desktop_hdm_account_addresses hd where txs.address=hd.address"; + private final static String inQueryTxHashOfDesktopHDMKeychain = " (" + queryTxHashOfHDAccount + ")"; + + private static DesktopTxProvider enDesktopTxProvider = + new DesktopTxProvider(ApplicationInstanceManager.txDBHelper); + + private TxDBHelper mDb; + + public static DesktopTxProvider getInstance() { + return enDesktopTxProvider; + } + + private DesktopTxProvider(TxDBHelper db) { + this.mDb = db; + } + + + private static final String insert_hdm_address_sql = "insert into desktop_hdm_account_addresses " + + "(path_type,address_index,is_issued,address,pub_key_1,pub_key_2,pub_key_3,is_synced)" + + " values (?,?,?,?,?,?,?,?) "; + + @Override + public void addAddress(List addressList) { + try { + this.mDb.getConn().setAutoCommit(false); + for (DesktopHDMAddress address : addressList) { + PreparedStatement stmt = this.mDb.getConn().prepareStatement(insert_hdm_address_sql); + String[] params = new String[]{Integer.toString(address.getPathType().getValue()), + Integer.toString(address.getIndex()), Integer.toString(address.isIssued() ? 1 : 0), + address.getAddress(), Base58.encode(address.getPubHot()) + , Base58.encode(address.getPubCold()), Base58.encode(address.getPubRemote()), Integer.toString(address.isSyncComplete() ? 1 : 0) + }; + if (params != null) { + for (int i = 0; i < params.length; i++) { + stmt.setString(i + 1, params[i]); + } + } + stmt.executeUpdate(); + stmt.close(); + } + this.mDb.getConn().commit(); + + } catch (SQLException e) { + e.printStackTrace(); + } + + } + + @Override + public int maxHDMAddressPubIndex() { + int maxIndex = -1; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select ifnull(max(address_index),-1) address_index from desktop_hdm_account_addresses ", null); + ResultSet cursor = statement.executeQuery(); + + if (cursor.next()) { + int idColumn = cursor.findColumn(AbstractDb.HDMAddressesColumns.HD_SEED_INDEX); + if (idColumn != -1) { + maxIndex = cursor.getInt(idColumn); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return maxIndex; + } + + @Override + public String externalAddress() { + String address = null; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select address from desktop_hdm_account_addresses where path_type=? and is_issued=? order by address_index asc limit 1 ", + new String[]{Integer.toString(AbstractHD.PathType.EXTERNAL_ROOT_PATH.getValue()), "0"}); + ResultSet cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn(AbstractDb.HDAccountAddressesColumns.ADDRESS); + if (idColumn != -1) { + address = cursor.getString(idColumn); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return address; + } + + @Override + public boolean hasAddress() { + boolean hasAddress = false; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select count(address) cnt from desktop_hdm_account_addresses ", + null); + ResultSet cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn("cnt"); + if (idColumn != -1) { + hasAddress = cursor.getInt(idColumn) > 0; + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return hasAddress; + } + + @Override + public long getHDAccountConfirmedBanlance(int hdSeedId) { + long sum = 0; + String unspendOutSql = "select ifnull(sum(a.out_value),0) sum from outs a,txs b where a.tx_hash=b.tx_hash " + + " and a.out_status=? and a.enterprise_hd_account_id=? and b.block_no is not null"; + try { + PreparedStatement statement = this.mDb.getPreparedStatement(unspendOutSql, + new String[]{Integer.toString(Out.OutStatus.unspent.getValue()), Integer.toString(hdSeedId)}); + ResultSet c = statement.executeQuery(); + if (c.next()) { + int idColumn = c.findColumn("sum"); + if (idColumn != -1) { + sum = c.getLong(idColumn); + } + } + c.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return sum; + } + + @Override + public HashSet getBelongAccountAddresses(List addressList) { + HashSet addressSet = new HashSet(); + + List temp = new ArrayList(); + if (addressList != null) { + for (String str : addressList) { + temp.add(Utils.format("'%s'", str)); + } + } + try { + String sql = Utils.format("select address from desktop_hdm_account_addresses where address in (%s) " + , Utils.joinString(temp, ",")); + PreparedStatement statement = this.mDb.getPreparedStatement(sql, + null); + ResultSet cursor = statement.executeQuery(); + while (cursor.next()) { + int idColumn = cursor.findColumn(AbstractDb.HDAccountAddressesColumns.ADDRESS); + if (idColumn != -1) { + addressSet.add(cursor.getString(idColumn)); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + SystemUtil.maxUsedSize(); + return addressSet; + } + + @Override + public void updateIssuedIndex(AbstractHD.PathType pathType, int index) { + String sql = "update desktop_hdm_account_addresses set is_issued=? where path_type=? and address_index<=? "; + Connection conn = this.mDb.getConn(); + try { + String[] params = new String[]{ + "1", Integer.toString(pathType.getValue()), Integer.toString(index) + }; + PreparedStatement stmt = conn.prepareStatement(sql); + if (params != null) { + for (int i = 0; i < params.length; i++) { + stmt.setString(i + 1, params[i]); + } + } + stmt.executeUpdate(); + conn.commit(); + stmt.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public int issuedIndex(AbstractHD.PathType pathType) { + + int issuedIndex = -1; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select ifnull(max(address_index),-1) address_index from " + + "desktop_hdm_account_addresses where path_type=? and is_issued=? ", + new String[]{Integer.toString(pathType.getValue()), "1"}); + ResultSet cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn("address_index"); + if (idColumn != -1) { + issuedIndex = cursor.getInt(idColumn); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return issuedIndex; + } + + @Override + public int allGeneratedAddressCount(AbstractHD.PathType pathType) { + int count = 0; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select ifnull(count(address),0) count from " + + "desktop_hdm_account_addresses where path_type=? ", + new String[]{Integer.toString(pathType.getValue())}); + ResultSet cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn("count"); + if (idColumn != -1) { + count = cursor.getInt(idColumn); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return count; + } + + @Override + public List getHDAccountUnconfirmedTx() { + List txList = new ArrayList(); + HashMap txDict = new HashMap(); + try { + String sql = "select * from txs where tx_hash in" + + inQueryTxHashOfDesktopHDMKeychain + + " and block_no is null " + + " order by block_no desc"; + PreparedStatement statement = this.mDb.getPreparedStatement(sql, null); + ResultSet c = statement.executeQuery(); + while (c.next()) { + Tx txItem = TxHelper.applyCursor(c); + txItem.setIns(new ArrayList()); + txItem.setOuts(new ArrayList()); + txList.add(txItem); + txDict.put(new Sha256Hash(txItem.getTxHash()), txItem); + } + c.close(); + statement.close(); + sql = "select b.* " + + " from ins b, txs c " + + " where c.tx_hash in " + + inQueryTxHashOfDesktopHDMKeychain + + " and b.tx_hash=c.tx_hash and c.block_no is null " + + " order by b.tx_hash ,b.in_sn"; + statement = this.mDb.getPreparedStatement(sql, null); + c = statement.executeQuery(); + while (c.next()) { + In inItem = TxHelper.applyCursorIn(c); + Tx tx = txDict.get(new Sha256Hash(inItem.getTxHash())); + if (tx != null) { + tx.getIns().add(inItem); + } + } + c.close(); + statement.close(); + + sql = "select b.* " + + " from outs b, txs c " + + " where c.tx_hash in" + + inQueryTxHashOfDesktopHDMKeychain + + " and b.tx_hash=c.tx_hash and c.block_no is null " + + " order by b.tx_hash,b.out_sn"; + statement = this.mDb.getPreparedStatement(sql, null); + c = statement.executeQuery(); + while (c.next()) { + Out out = TxHelper.applyCursorOut(c); + Tx tx = txDict.get(new Sha256Hash(out.getTxHash())); + if (tx != null) { + tx.getOuts().add(out); + } + } + c.close(); + statement.close(); + + } catch (AddressFormatException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + return txList; + } + + @Override + public List getPubs(AbstractHD.PathType pathType) { + List pubList = new ArrayList(); + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select address_index,address,pub_key_1,pub_key_2,pub_key_3 " + + "from desktop_hdm_account_addresses where path_type=? ", + new String[]{Integer.toString(pathType.getValue())}); + ResultSet cursor = statement.executeQuery(); + while (cursor.next()) { + try { + HDMAddress.Pubs pubs = new HDMAddress.Pubs(); + int idColumn = cursor.findColumn("pub_key_1"); + if (idColumn != -1) { + pubs.hot = Base58.decode(cursor.getString(idColumn)); + } + idColumn = cursor.findColumn("pub_key_2"); + if (idColumn != -1) { + pubs.cold = Base58.decode(cursor.getString(idColumn)); + } + idColumn = cursor.findColumn("pub_key_3"); + if (idColumn != -1) { + pubs.remote = Base58.decode(cursor.getString(idColumn)); + } + idColumn = cursor.findColumn("address_index"); + if (idColumn != -1) { + pubs.index = cursor.getInt(idColumn); + } + pubList.add(pubs); + } catch (AddressFormatException e) { + e.printStackTrace(); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return pubList; + } + + @Override + public int getUnspendOutCountByHDAccountWithPath(int hdAccountId, AbstractHD.PathType pathType) { + int result = 0; + String sql = "select count(tx_hash) cnt from outs where out_address in " + + "(select address from desktop_hdm_account_addresses where path_type =? and out_status=?) " + + "and enterprise_hd_account_id=?"; + try { + PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Integer.toString(pathType.getValue()) + , Integer.toString(Out.OutStatus.unspent.getValue()) + , Integer.toString(hdAccountId) + }); + ResultSet c = statement.executeQuery(); + if (c.next()) { + int idColumn = c.findColumn("cnt"); + if (idColumn != -1) { + result = c.getInt(idColumn); + } + } + c.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return result; + } + + @Override + public int unSyncedAddressCount() { + int cnt = 0; + try { + String sql = "select count(address) cnt from desktop_hdm_account_addresses where is_synced=? "; + PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{"0"}); + ResultSet cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn("cnt"); + if (idColumn != -1) { + cnt = cursor.getInt(idColumn); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return cnt; + } + + @Override + public List getUnspendOutByHDAccountWithPath(int hdAccountId, AbstractHD.PathType pathType) { + List outList = new ArrayList(); + + String sql = "select * from outs where out_address in " + + "(select address from desktop_hdm_account_addresses where path_type =? and out_status=?) " + + "and enterprise_hd_account_id=?"; + try { + PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Integer.toString(pathType.getValue()) + , Integer.toString(Out.OutStatus.unspent.getValue()) + , Integer.toString(hdAccountId) + }); + ResultSet c = statement.executeQuery(); + while (c.next()) { + outList.add(TxHelper.applyCursorOut(c)); + } + c.close(); + statement.close(); + } catch (AddressFormatException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + + return outList; + } + + @Override + public DesktopHDMAddress addressForPath(DesktopHDMKeychain keychain, AbstractHD.PathType type, int index) { + + DesktopHDMAddress accountAddress = null; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select * from desktop_hdm_account_addresses where path_type=? and address_index=? ", + new String[]{Integer.toString(type.getValue()), Integer.toString(index)}); + ResultSet cursor = statement.executeQuery(); + + if (cursor.next()) { + accountAddress = formatAddress(keychain, cursor); + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return accountAddress; + } + + @Override + public List getSigningAddressesForInputs(DesktopHDMKeychain keychain, List inList) { + List desktopHDMAddresses = + new ArrayList(); + ResultSet c; + try { + for (In in : inList) { + String sql = "select a.*" + + " from desktop_hdm_account_addresses a ,outs b" + + " where a.address=b.out_address" + + " and b.tx_hash=? and b.out_sn=? "; + OutPoint outPoint = in.getOutpoint(); + PreparedStatement statement = this.mDb.getPreparedStatement(sql, + new String[]{Base58.encode(in.getPrevTxHash()), + Integer.toString(outPoint.getOutSn())}); + c = statement.executeQuery(); + if (c.next()) { + desktopHDMAddresses.add(formatAddress(keychain, c)); + } + c.close(); + statement.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return desktopHDMAddresses; + } + + @Override + public List belongAccount(DesktopHDMKeychain keychain, List addresses) { + List desktopHDMAddresses = new ArrayList(); + List temp = new ArrayList(); + for (String str : addresses) { + temp.add(Utils.format("'%s'", str)); + } + String sql = "select * from desktop_hdm_account_addresses where address in (" + Utils.joinString(temp, ",") + ")"; + try { + PreparedStatement statement = this.mDb.getPreparedStatement(sql, null); + ResultSet cursor = statement.executeQuery(); + while (cursor.next()) { + desktopHDMAddresses.add(formatAddress(keychain, cursor)); + + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return desktopHDMAddresses; + } + + @Override + public void updateSyncdForIndex(AbstractHD.PathType pathType, int index) { + this.mDb.executeUpdate("update desktop_hdm_account_addresses set is_synced=? where path_type=? and address_index>? " + , new String[]{"1", Integer.toString(pathType.getValue()), Integer.toString(index)}); + + } + + @Override + public void updateSyncdComplete(DesktopHDMAddress address) { + + String sql = "update desktop_hdm_account_addresses set is_synced=? where address=? "; + Connection conn = this.mDb.getConn(); + try { + String[] params = new String[]{ + Integer.toString(address.isSyncComplete() ? 1 : 0), address.getAddress() + }; + PreparedStatement stmt = conn.prepareStatement(sql); + if (params != null) { + for (int i = 0; i < params.length; i++) { + stmt.setString(i + 1, params[i]); + } + } + stmt.executeUpdate(); + conn.commit(); + stmt.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + + } + + private DesktopHDMAddress formatAddress(DesktopHDMKeychain keychain, ResultSet c) throws SQLException { + String address = null; + AbstractHD.PathType ternalRootType = AbstractHD.PathType.EXTERNAL_ROOT_PATH; + boolean isIssued = false; + boolean isSynced = true; + HDMAddress.Pubs pubs = new HDMAddress.Pubs(); + DesktopHDMAddress hdAccountAddress = null; + try { + int idColumn = c.findColumn("address"); + if (idColumn != -1) { + address = c.getString(idColumn); + } + idColumn = c.findColumn("path_type"); + if (idColumn != -1) { + ternalRootType = AbstractHD.getTernalRootType(c.getInt(idColumn)); + + } + idColumn = c.findColumn("address_index"); + if (idColumn != -1) { + pubs.index = c.getInt(idColumn); + } + idColumn = c.findColumn("pub_key_1"); + if (idColumn != -1) { + pubs.hot = Base58.decode(c.getString(idColumn)); + } + idColumn = c.findColumn("pub_key_2"); + if (idColumn != -1) { + pubs.cold = Base58.decode(c.getString(idColumn)); + } + idColumn = c.findColumn("pub_key_3"); + if (idColumn != -1) { + pubs.remote = Base58.decode(c.getString(idColumn)); + } + + idColumn = c.findColumn("is_issued"); + if (idColumn != -1) { + isIssued = c.getInt(idColumn) == 1; + } + idColumn = c.findColumn("is_synced"); + if (idColumn != -1) { + isSynced = c.getInt(idColumn) == 1; + } + hdAccountAddress = new DesktopHDMAddress(pubs, address, + ternalRootType, isIssued, isSynced, keychain); + } catch (AddressFormatException e) { + e.printStackTrace(); + } + return hdAccountAddress; + } + + + public void setSyncdNotComplete() { + this.mDb.executeUpdate("update desktop_hdm_account_addresses set is_synced=?", new String[]{"0"}); + } + + @Override + public List getUnspendOutByHDAccount(int hdAccountId) { + List outItems = new ArrayList(); + String unspendOutSql = "select a.* from outs a,txs b where a.tx_hash=b.tx_hash " + + " and a.out_status=? and a.enterprise_hd_account_id=?"; + try { + PreparedStatement statement = this.mDb.getPreparedStatement(unspendOutSql, + new String[]{Integer.toString(Out.OutStatus.unspent.getValue()), Integer.toString(hdAccountId)}); + ResultSet c = statement.executeQuery(); + while (c.next()) { + outItems.add(TxHelper.applyCursorOut(c)); + } + + c.close(); + statement.close(); + } catch (AddressFormatException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + return outItems; + } +} diff --git a/src/main/java/net/bither/db/EnterpriseHDMProvider.java b/src/main/java/net/bither/db/EnterpriseHDMProvider.java new file mode 100644 index 0000000..f640b54 --- /dev/null +++ b/src/main/java/net/bither/db/EnterpriseHDMProvider.java @@ -0,0 +1,101 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.db; + +import net.bither.ApplicationInstanceManager; +import net.bither.bitherj.core.EnterpriseHDMAddress; +import net.bither.bitherj.core.EnterpriseHDMKeychain; +import net.bither.bitherj.db.IEnterpriseHDMProvider; + +import java.util.List; + +public class EnterpriseHDMProvider implements IEnterpriseHDMProvider { + private static EnterpriseHDMProvider enterpriseHDMProvider = + new EnterpriseHDMProvider(ApplicationInstanceManager.addressDBHelper); + + public static EnterpriseHDMProvider getInstance() { + return enterpriseHDMProvider; + } + + private EnterpriseHDMProvider(AddressDBHelper db) { + this.mDb = db; + } + + private AddressDBHelper mDb; + + @Override + public String getEnterpriseEncryptMnemonicSeed(int hdSeedId) { + return null; + } + + @Override + public String getEnterpriseEncryptHDSeed(int hdSeedId) { + return null; + } + + @Override + public String getEnterpriseHDFristAddress(int hdSeedId) { + return null; + } + + @Override + public boolean isEnterpriseHDMSeedFromXRandom(int hdSeedId) { + return false; + } + + @Override + public void addEnterpriseHDMAddress(List enterpriseHDMAddressList) { + + } + + @Override + public List getEnterpriseHDMAddress(EnterpriseHDMKeychain keychain) { + return null; + } + + @Override + public void addMultiSignSet(int n, int m) { + + } + + @Override + public void updateSyncComplete(EnterpriseHDMAddress enterpriseHDMAddress) { + + } + + @Override + public List getEnterpriseHDMKeychainIds() { + return null; + } + + @Override + public int getEnterpriseHDMSeedId() { + return 0; + } + + @Override + public int getPubCount() { + return 0; + } + + @Override + public int getThreshold() { + return 0; + } +} diff --git a/src/main/java/net/bither/db/HDAccount2Provider.java b/src/main/java/net/bither/db/HDAccount2Provider.java new file mode 100644 index 0000000..114f696 --- /dev/null +++ b/src/main/java/net/bither/db/HDAccount2Provider.java @@ -0,0 +1,109 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.db; + +import net.bither.ApplicationInstanceManager; +import net.bither.bitherj.crypto.PasswordSeed; +import net.bither.bitherj.db.imp.AbstractHDAccountProvider; +import net.bither.bitherj.db.imp.base.IDb; +import net.bither.bitherj.utils.Base58; +import net.bither.db.base.JavaDb; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +public class HDAccount2Provider extends AbstractHDAccountProvider { + + private static HDAccount2Provider hdAccountProvider = new HDAccount2Provider(ApplicationInstanceManager.addressDBHelper); + + public static HDAccount2Provider getInstance() { + return hdAccountProvider; + } + + private AddressDBHelper helper; + + public HDAccount2Provider(AddressDBHelper helper) { + this.helper = helper; + } + + @Override + public IDb getReadDb() { + return new JavaDb(this.helper.getConn()); + } + + @Override + public IDb getWriteDb() { + return new JavaDb(this.helper.getConn()); + } + + @Override + protected int insertHDAccountToDb(IDb db, String encryptedMnemonicSeed, String encryptSeed, String firstAddress, boolean isXrandom, byte[] externalPub, byte[] internalPub) { + try { + String sql = "insert into hd_account(encrypt_seed,encrypt_mnemonic_seed,is_xrandom,hd_address,external_pub,internal_pub) values(?,?,?,?,?,?);"; + PreparedStatement stmt = ((JavaDb) db).getConnection().prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + + stmt.setString(1, encryptSeed); + stmt.setString(2, encryptedMnemonicSeed); + stmt.setInt(3, isXrandom ? 1 : 0); + stmt.setString(4, firstAddress); + stmt.setString(5, Base58.encode(externalPub)); + stmt.setString(6, Base58.encode(internalPub)); + stmt.executeUpdate(); + ResultSet tableKeys = stmt.getGeneratedKeys(); + tableKeys.next(); + stmt.close(); + return tableKeys.getInt(1); + } catch (SQLException e) { + e.printStackTrace(); + return -1; + } + } + + @Override + protected int insertMonitorHDAccountToDb(IDb db, String firstAddress, boolean isXrandom, byte[] externalPub, byte[] internalPub) { + try { + String sql = "insert into hd_account(is_xrandom,hd_address,external_pub,internal_pub) values(?,?,?,?);"; + PreparedStatement stmt = ((JavaDb) db).getConnection().prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + stmt.setInt(1, isXrandom ? 1 : 0); + stmt.setString(2, firstAddress); + stmt.setString(3, Base58.encode(externalPub)); + stmt.setString(4, Base58.encode(internalPub)); + stmt.executeUpdate(); + ResultSet tableKeys = stmt.getGeneratedKeys(); + tableKeys.next(); + stmt.close(); + return tableKeys.getInt(1); + } catch (SQLException e) { + e.printStackTrace(); + return -1; + } + } + + @Override + protected boolean hasPasswordSeed(IDb db) { + return Address2Provider.getInstance().hasPasswordSeed(db); + } + + @Override + protected void addPasswordSeed(IDb db, PasswordSeed passwordSeed) { + Address2Provider.getInstance().addPasswordSeed(db, passwordSeed); + } +} diff --git a/src/main/java/net/bither/db/HDAccountAddress2Provider.java b/src/main/java/net/bither/db/HDAccountAddress2Provider.java new file mode 100644 index 0000000..85737f4 --- /dev/null +++ b/src/main/java/net/bither/db/HDAccountAddress2Provider.java @@ -0,0 +1,49 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.db; + +import net.bither.ApplicationInstanceManager; +import net.bither.bitherj.db.imp.AbstractHDAccountAddressProvider; +import net.bither.bitherj.db.imp.base.IDb; +import net.bither.db.base.JavaDb; + +public class HDAccountAddress2Provider extends AbstractHDAccountAddressProvider { + + private static HDAccountAddress2Provider hdAccountAddressProvider = new HDAccountAddress2Provider(ApplicationInstanceManager.txDBHelper); + + public static HDAccountAddress2Provider getInstance() { + return hdAccountAddressProvider; + } + + private TxDBHelper helper; + + public HDAccountAddress2Provider(TxDBHelper helper) { + this.helper = helper; + } + + @Override + public IDb getReadDb() { + return new JavaDb(this.helper.getConn()); + } + + @Override + public IDb getWriteDb() { + return new JavaDb(this.helper.getConn()); + } +} diff --git a/src/main/java/net/bither/db/HDAccountAddressProvider.java b/src/main/java/net/bither/db/HDAccountAddressProvider.java new file mode 100644 index 0000000..8f62a38 --- /dev/null +++ b/src/main/java/net/bither/db/HDAccountAddressProvider.java @@ -0,0 +1,943 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.db; + +import net.bither.ApplicationInstanceManager; +import net.bither.bitherj.BitherjSettings; +import net.bither.bitherj.core.*; +import net.bither.bitherj.db.AbstractDb; +import net.bither.bitherj.db.IHDAccountAddressProvider; +import net.bither.bitherj.exception.AddressFormatException; +import net.bither.bitherj.utils.Base58; +import net.bither.bitherj.utils.Sha256Hash; +import net.bither.bitherj.utils.Utils; +import net.bither.utils.SystemUtil; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +public class HDAccountAddressProvider implements IHDAccountAddressProvider { + + private final static String queryTxHashOfHDAccount = " select distinct txs.tx_hash from addresses_txs txs ,hd_account_addresses hd where txs.address=hd.address"; + private final static String inQueryTxHashOfHDAccount = " (" + queryTxHashOfHDAccount + ")"; + + + private static HDAccountAddressProvider txProvider = new HDAccountAddressProvider(ApplicationInstanceManager.txDBHelper); + + public static HDAccountAddressProvider getInstance() { + return txProvider; + } + + private TxDBHelper mDb; + + public HDAccountAddressProvider(TxDBHelper db) { + this.mDb = db; + } + + @Override + public void addAddress(List hdAccountAddresses) { + try { + this.mDb.getConn().setAutoCommit(false); + Connection conn = this.mDb.getConn(); + for (HDAccount.HDAccountAddress hdAccountAddress : hdAccountAddresses) { + addAddress(conn, hdAccountAddress); + } + conn.commit(); + + } catch (SQLException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + + } + + @Override + public int issuedIndex(int hdAccountId, AbstractHD.PathType pathType) { + int issuedIndex = -1; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select ifnull(max(address_index),-1) address_index from " + + AbstractDb.Tables.HD_ACCOUNT_ADDRESS + + " where path_type=? and is_issued=? and hd_account_id=? ", + new String[]{Integer.toString(pathType.getValue()), "1", Integer.toString(hdAccountId)}); + ResultSet cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn(AbstractDb.HDAccountAddressesColumns.ADDRESS_INDEX); + if (idColumn != -1) { + issuedIndex = cursor.getInt(idColumn); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return issuedIndex; + } + + @Override + public int allGeneratedAddressCount(int hdAccountId, AbstractHD.PathType pathType) { + int count = 0; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select ifnull(count(address),0) count from " + + AbstractDb.Tables.HD_ACCOUNT_ADDRESS + " where path_type=? and hd_account_id=? ", + new String[]{Integer.toString(pathType.getValue()), Integer.toString(hdAccountId)}); + ResultSet cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn("count"); + if (idColumn != -1) { + count = cursor.getInt(idColumn); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return count; + } + + @Override + public void updateIssuedIndex(int hdAccountId, AbstractHD.PathType pathType, int index) { + String sql = "update hd_account_addresses set is_issued=? where path_type=? and address_index<=? and hd_account_id=?"; + Connection conn = this.mDb.getConn(); + try { + String[] params = new String[]{ + "1", Integer.toString(pathType.getValue()), Integer.toString(index), Integer.toString(hdAccountId) + }; + PreparedStatement stmt = conn.prepareStatement(sql); + if (params != null) { + for (int i = 0; i < params.length; i++) { + stmt.setString(i + 1, params[i]); + } + } + stmt.executeUpdate(); + conn.commit(); + stmt.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public String externalAddress(int hdAccountId) { + String address = null; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select address from " + AbstractDb.Tables.HD_ACCOUNT_ADDRESS + + " where path_type=? and is_issued=? and hd_account_id=? order by address_index asc limit 1 ", + new String[]{Integer.toString(AbstractHD.PathType.EXTERNAL_ROOT_PATH.getValue()), "0", Integer.toString(hdAccountId)}); + ResultSet cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn(AbstractDb.HDAccountAddressesColumns.ADDRESS); + if (idColumn != -1) { + address = cursor.getString(idColumn); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return address; + } + + @Override + public HashSet getBelongAccountAddresses(int hdAccountId, List addressList) { + HashSet addressSet = new HashSet(); + + List temp = new ArrayList(); + if (addressList != null) { + for (String str : addressList) { + temp.add(Utils.format("'%s'", str)); + } + } + try { + String sql = Utils.format("select address from hd_account_addresses where hd_account_id=? address in (%s) " + , Utils.joinString(temp, ",")); + PreparedStatement statement = this.mDb.getPreparedStatement(sql, + new String[] {Integer.toString(hdAccountId)}); + ResultSet cursor = statement.executeQuery(); + while (cursor.next()) { + int idColumn = cursor.findColumn(AbstractDb.HDAccountAddressesColumns.ADDRESS); + if (idColumn != -1) { + addressSet.add(cursor.getString(idColumn)); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + SystemUtil.maxUsedSize(); + return addressSet; + } + + @Override + public HashSet getBelongAccountAddresses(List addressList) { + HashSet addressSet = new HashSet(); + + List temp = new ArrayList(); + if (addressList != null) { + for (String str : addressList) { + temp.add(Utils.format("'%s'", str)); + } + } + String sql = Utils.format("select address from hd_account_addresses where address in (%s) " + , Utils.joinString(temp, ",")); + try { + PreparedStatement statement = this.mDb.getPreparedStatement(sql, null); + ResultSet cursor = statement.executeQuery(); + while (cursor.next()) { + int idColumn = cursor.findColumn(AbstractDb.HDAccountAddressesColumns.ADDRESS); + if (idColumn != -1) { + addressSet.add(cursor.getString(idColumn)); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + + + return addressSet; + } + + @Override + public Tx updateOutHDAccountId(Tx tx) { + List addressList = tx.getOutAddressList(); + if (addressList != null && addressList.size() > 0) { + HashSet set = new HashSet(); + set.addAll(addressList); + StringBuilder strBuilder = new StringBuilder(); + for (String str : set) { + strBuilder.append("'").append(str).append("',"); + } + + String sql = Utils.format("select address,hd_account_id from hd_account_addresses where address in (%s) " + , strBuilder.substring(0, strBuilder.length() - 1)); + try { + PreparedStatement statement = this.mDb.getPreparedStatement(sql, null); + ResultSet cursor = statement.executeQuery(); + while (cursor.next()) { + String address = cursor.getString(1); + int hdAccountId = cursor.getInt(2); + for (Out out: tx.getOuts()) { + if (Utils.compareString(out.getOutAddress(), address)) { + out.setHDAccountId(hdAccountId); + } + } + } + cursor.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + return tx; + } + + @Override + public int getRelatedAddressCnt(List addresses) { + int cnt = 0; + if (addresses != null && addresses.size() > 0) { + HashSet set = new HashSet(); + set.addAll(addresses); + StringBuilder strBuilder = new StringBuilder(); + for (String str : set) { + strBuilder.append("'").append(str).append("',"); + } + String sql = Utils.format("select count(0) cnt from hd_account_addresses where address in (%s) " + , strBuilder.substring(0, strBuilder.length() - 1)); + + try { + PreparedStatement statement = this.mDb.getPreparedStatement(sql, null); + ResultSet c = statement.executeQuery(); + if (c.next()) { + cnt = c.getInt(1); + } + c.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + return cnt; + } + + @Override + public List getRelatedHDAccountIdList(List addresses) { + List hdAccountIdList = new ArrayList(); + if (addresses != null && addresses.size() > 0) { + HashSet set = new HashSet(); + set.addAll(addresses); + StringBuilder strBuilder = new StringBuilder(); + for (String str : set) { + strBuilder.append("'").append(str).append("',"); + } + + String sql = Utils.format("select distinct hd_account_id from hd_account_addresses where address in (%s) " + , strBuilder.substring(0, strBuilder.length() - 1)); + PreparedStatement statement = null; + try { + statement = this.mDb.getPreparedStatement(sql, null); + ResultSet c = statement.executeQuery(); + + while (c.next()) { + hdAccountIdList.add(c.getInt(1)); + } + c.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + return hdAccountIdList; + } + + @Override + public HDAccount.HDAccountAddress addressForPath(int hdAccountId, AbstractHD.PathType type, int index) { + HDAccount.HDAccountAddress accountAddress = null; + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select address,pub,path_type,address_index,is_issued,is_synced from " + + AbstractDb.Tables.HD_ACCOUNT_ADDRESS + " where path_type=? and address_index=? and hd_account_id=? ", + new String[]{Integer.toString(type.getValue()), Integer.toString(index), Integer.toString(hdAccountId)}); + ResultSet cursor = statement.executeQuery(); + + if (cursor.next()) { + accountAddress = formatAddress(cursor); + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return accountAddress; + } + + @Override + public List getPubs(int hdAccountId, AbstractHD.PathType pathType) { + List adressPubList = new ArrayList(); + try { + PreparedStatement statement = this.mDb.getPreparedStatement("select pub from hd_account_addresses where path_type=? and hd_account_id=? ", + new String[]{Integer.toString(pathType.getValue()), Integer.toString(hdAccountId)}); + ResultSet cursor = statement.executeQuery(); + while (cursor.next()) { + try { + int idColumn = cursor.findColumn(AbstractDb.HDAccountAddressesColumns.PUB); + if (idColumn != -1) { + adressPubList.add(Base58.decode(cursor.getString(idColumn))); + } + } catch (AddressFormatException e) { + e.printStackTrace(); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return adressPubList; + } + + @Override + public List belongAccount(int hdAccountId, List addresses) { + List hdAccountAddressList = new ArrayList(); + List temp = new ArrayList(); + for (String str : addresses) { + temp.add(Utils.format("'%s'", str)); + } + String sql = "select address,pub,path_type,address_index,is_issued,is_synced from " + AbstractDb.Tables.HD_ACCOUNT_ADDRESS + + " where hd_account_id=? and address in (" + Utils.joinString(temp, ",") + ")"; + try { + PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[] {Integer.toString(hdAccountId)}); + ResultSet cursor = statement.executeQuery(); + while (cursor.next()) { + hdAccountAddressList.add(formatAddress(cursor)); + + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return hdAccountAddressList; + } + + @Override + public void updateSyncdComplete(int hdAccountId, HDAccount.HDAccountAddress address) { + String sql = "update hd_account_addresses set is_synced=? where address=? and hd_account_id=? "; + Connection conn = this.mDb.getConn(); + try { + String[] params = new String[]{ + Integer.toString(address.isSyncedComplete() ? 1 : 0), address.getAddress() + , Integer.toString(hdAccountId) + }; + PreparedStatement stmt = conn.prepareStatement(sql); + if (params != null) { + for (int i = 0; i < params.length; i++) { + stmt.setString(i + 1, params[i]); + } + } + stmt.executeUpdate(); + conn.commit(); + stmt.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public void setSyncedNotComplete() { + this.mDb.executeUpdate("update hd_account_addresses set is_synced=?", new String[]{"0"}); + } + + @Override + public int unSyncedAddressCount(int hdAccountId) { + int cnt = 0; + try { + String sql = "select count(address) cnt from hd_account_addresses where is_synced=? and hd_account_id=? "; + PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{"0", Integer.toString(hdAccountId)}); + ResultSet cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn("cnt"); + if (idColumn != -1) { + cnt = cursor.getInt(idColumn); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return cnt; + } + + @Override + public void updateSyncedForIndex(int hdAccountId, AbstractHD.PathType pathType, int index) { + this.mDb.executeUpdate("update hd_account_addresses set is_synced=? where path_type=? and address_index>? and hd_account_id=? " + , new String[]{"1", Integer.toString(pathType.getValue()), Integer.toString(index), Integer.toString(hdAccountId)}); + + } + + @Override + public List getSigningAddressesForInputs(int hdAccountId, List inList) { + + List hdAccountAddressList = + new ArrayList(); + ResultSet c; + try { + for (In in : inList) { + String sql = "select a.*" + + " from hd_account_addresses a ,outs b" + + " where a.address=b.out_address" + + " and b.tx_hash=? and b.out_sn=? and a.hd_account_id=? "; + OutPoint outPoint = in.getOutpoint(); + PreparedStatement statement = this.mDb.getPreparedStatement(sql, + new String[]{Base58.encode(in.getPrevTxHash()), + Integer.toString(outPoint.getOutSn()), Integer.toString(hdAccountId)}); + c = statement.executeQuery(); + if (c.next()) { + hdAccountAddressList.add(formatAddress(c)); + } + c.close(); + statement.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return hdAccountAddressList; + } + + @Override + public int hdAccountTxCount(int hdAccountId) { + int result = 0; + try { + String sql = "select count( distinct a.tx_hash) cnt from addresses_txs a ,hd_account_addresses b where a.address=b.address and b.hd_account_id=? "; + PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[] {Integer.toString(hdAccountId)}); + ResultSet c = statement.executeQuery(); + if (c.next()) { + int idColumn = c.findColumn("cnt"); + if (idColumn != -1) { + result = c.getInt(idColumn); + } + } + c.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return result; + } + + @Override + public long getHDAccountConfirmedBalance(int hdAccountId) { + long sum = 0; + String unspendOutSql = "select ifnull(sum(a.out_value),0) sum from outs a,txs b where a.tx_hash=b.tx_hash " + + " and a.out_status=? and a.hd_account_id=? and b.block_no is not null"; + try { + PreparedStatement statement = this.mDb.getPreparedStatement(unspendOutSql, + new String[]{Integer.toString(Out.OutStatus.unspent.getValue()), Integer.toString(hdAccountId)}); + ResultSet c = statement.executeQuery(); + if (c.next()) { + int idColumn = c.findColumn("sum"); + if (idColumn != -1) { + sum = c.getLong(idColumn); + } + } + c.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return sum; + } + + @Override + public List getHDAccountUnconfirmedTx(int hdAccountId) { + List txList = new ArrayList(); + + HashMap txDict = new HashMap(); + + try { + String sql = "select distinct a.* " + + " from txs a,addresses_txs b,hd_account_addresses c" + + " where a.tx_hash=b.tx_hash and b.address=c.address and c.hd_account_id=? and a.block_no is null" + + " order by a.tx_hash"; +// String sql = "select * from txs where tx_hash in" + +// inQueryTxHashOfHDAccount + +// " and block_no is null " + +// " order by block_no desc"; + PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[] {Integer.toString(hdAccountId)}); + ResultSet c = statement.executeQuery(); + while (c.next()) { + Tx txItem = TxHelper.applyCursor(c); + txItem.setIns(new ArrayList()); + txItem.setOuts(new ArrayList()); + txList.add(txItem); + txDict.put(new Sha256Hash(txItem.getTxHash()), txItem); + } + c.close(); + statement.close(); + sql = "select distinct a.* " + + " from ins a, txs b,addresses_txs c,hd_account_addresses d" + + " where a.tx_hash=b.tx_hash and b.tx_hash=c.tx_hash and c.address=d.address" + + " and b.block_no is null and d.hd_account_id=?" + + " order by a.tx_hash,a.in_sn"; +// sql = "select b.* " + +// " from ins b, txs c " + +// " where c.tx_hash in " + +// inQueryTxHashOfHDAccount + +// " and b.tx_hash=c.tx_hash and c.block_no is null " + +// " order by b.tx_hash ,b.in_sn"; + statement = this.mDb.getPreparedStatement(sql, new String[] {Integer.toString(hdAccountId)}); + c = statement.executeQuery(); + while (c.next()) { + In inItem = TxHelper.applyCursorIn(c); + Tx tx = txDict.get(new Sha256Hash(inItem.getTxHash())); + if (tx != null) { + tx.getIns().add(inItem); + } + } + c.close(); + statement.close(); + + sql = "select distinct a.* " + + " from outs a, txs b,addresses_txs c,hd_account_addresses d" + + " where a.tx_hash=b.tx_hash and b.tx_hash=c.tx_hash and c.address=d.address" + + " and b.block_no is null and d.hd_account_id=?" + + " order by a.tx_hash,a.out_sn"; +// sql = "select b.* " + +// " from outs b, txs c " + +// " where c.tx_hash in" + +// inQueryTxHashOfHDAccount + +// " and b.tx_hash=c.tx_hash and c.block_no is null " + +// " order by b.tx_hash,b.out_sn"; + statement = this.mDb.getPreparedStatement(sql, new String[] {Integer.toString(hdAccountId)}); + c = statement.executeQuery(); + while (c.next()) { + Out out = TxHelper.applyCursorOut(c); + Tx tx = txDict.get(new Sha256Hash(out.getTxHash())); + if (tx != null) { + tx.getOuts().add(out); + } + } + c.close(); + statement.close(); + + } catch (AddressFormatException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + return txList; + } + + @Override + public long sentFromAccount(int hdAccountId, byte[] txHash) { + String sql = "select sum(o.out_value) out_value from ins i,outs o where" + + " i.tx_hash=? and o.tx_hash=i.prev_tx_hash and i.prev_out_sn=o.out_sn and o.hd_account_id=?"; + long sum = 0; + + ResultSet cursor; + + try { + PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Base58.encode(txHash), + Integer.toString(hdAccountId)}); + cursor = statement.executeQuery(); + if (cursor.next()) { + int idColumn = cursor.findColumn(AbstractDb.OutsColumns.OUT_VALUE); + if (idColumn != -1) { + sum = cursor.getLong(idColumn); + } + } + cursor.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + + return sum; + } + + @Override + public List getTxAndDetailByHDAccount(int hdAccountId) { + List txItemList = new ArrayList(); + + HashMap txDict = new HashMap(); + + try { + String sql = "select distinct a.* " + + " from txs a,addresses_txs b,hd_account_addresses c" + + " where a.tx_hash=b.tx_hash and b.address=c.address and c.hd_account_id=?" + + " order by ifnull(block_no,4294967295) desc,a.tx_hash"; +// String sql = "select * from txs where tx_hash in " + +// inQueryTxHashOfHDAccount + +// " order by" + +// " ifnull(block_no,4294967295) desc "; + PreparedStatement statement = this.mDb.getPreparedStatement(sql, null); + ResultSet c = statement.executeQuery(); + StringBuilder txsStrBuilder = new StringBuilder(); + while (c.next()) { + Tx txItem = TxHelper.applyCursor(c); + txItem.setIns(new ArrayList()); + txItem.setOuts(new ArrayList()); + txItemList.add(txItem); + txDict.put(new Sha256Hash(txItem.getTxHash()), txItem); + txsStrBuilder.append("'").append(Base58.encode(txItem.getTxHash())).append("'").append(","); + } + c.close(); + statement.close(); + + if (txsStrBuilder.length() > 1) { + String txs = txsStrBuilder.substring(0, txsStrBuilder.length() - 1); + sql = Utils.format("select b.* from ins b where b.tx_hash in (%s)" + + " order by b.tx_hash ,b.in_sn", txs); + statement = this.mDb.getPreparedStatement(sql, null); + c = statement.executeQuery(); + while (c.next()) { + In inItem = TxHelper.applyCursorIn(c); + Tx tx = txDict.get(new Sha256Hash(inItem.getTxHash())); + if (tx != null) { + tx.getIns().add(inItem); + } + } + c.close(); + statement.close(); + + sql = Utils.format("select b.* from outs b where b.tx_hash in (%s)" + + " order by b.tx_hash,b.out_sn", txs); + statement = this.mDb.getPreparedStatement(sql, null); + c = statement.executeQuery(); + while (c.next()) { + Out out = TxHelper.applyCursorOut(c); + Tx tx = txDict.get(new Sha256Hash(out.getTxHash())); + if (tx != null) { + tx.getOuts().add(out); + } + } + c.close(); + statement.close(); + } + } catch (AddressFormatException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + return txItemList; + } + + @Override + public List getTxAndDetailByHDAccount(int hdAccountId, int page) { + List txItemList = new ArrayList(); + + HashMap txDict = new HashMap(); + + + try { + String sql = "select distinct a.* " + + " from txs a,addresses_txs b,hd_account_addresses c" + + " where a.tx_hash=b.tx_hash and b.address=c.address and c.hd_account_id=?" + + " order by ifnull(block_no,4294967295) desc,a.tx_hash" + + " limit ?,?"; +// String sql = "select * from txs where tx_hash in " + +// inQueryTxHashOfHDAccount + +// " order by" + +// " ifnull(block_no,4294967295) desc limit ?,? "; + PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Integer.toString(hdAccountId) + , Integer.toString((page - 1) * BitherjSettings.TX_PAGE_SIZE) + , Integer.toString(BitherjSettings.TX_PAGE_SIZE) + }); + ResultSet c = statement.executeQuery(); + StringBuilder txsStrBuilder = new StringBuilder(); + while (c.next()) { + Tx txItem = TxHelper.applyCursor(c); + txItem.setIns(new ArrayList()); + txItem.setOuts(new ArrayList()); + txItemList.add(txItem); + txDict.put(new Sha256Hash(txItem.getTxHash()), txItem); + txsStrBuilder.append("'").append(Base58.encode(txItem.getTxHash())).append("'").append(","); + } + c.close(); + statement.close(); + + if (txsStrBuilder.length() > 1) { + String txs = txsStrBuilder.substring(0, txsStrBuilder.length() - 1); + sql = Utils.format("select b.* from ins b where b.tx_hash in (%s)" + + " order by b.tx_hash ,b.in_sn", txs); + statement = this.mDb.getPreparedStatement(sql, null); + c = statement.executeQuery(); + while (c.next()) { + In inItem = TxHelper.applyCursorIn(c); + Tx tx = txDict.get(new Sha256Hash(inItem.getTxHash())); + if (tx != null) { + tx.getIns().add(inItem); + } + } + c.close(); + statement.close(); + + sql = Utils.format("select b.* from outs b where b.tx_hash in (%s)" + + " order by b.tx_hash,b.out_sn", txs); + statement = this.mDb.getPreparedStatement(sql, null); + c = statement.executeQuery(); + while (c.next()) { + Out out = TxHelper.applyCursorOut(c); + Tx tx = txDict.get(new Sha256Hash(out.getTxHash())); + if (tx != null) { + tx.getOuts().add(out); + } + } + c.close(); + statement.close(); + + } + } catch (AddressFormatException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + return txItemList; + } + + @Override + public List getUnspendOutByHDAccount(int hdAccountId) { + List outItems = new ArrayList(); + String unspendOutSql = "select a.* from outs a,txs b where a.tx_hash=b.tx_hash " + + " and a.out_status=? and a.hd_account_id=?"; + try { + PreparedStatement statement = this.mDb.getPreparedStatement(unspendOutSql, + new String[]{Integer.toString(Out.OutStatus.unspent.getValue()), Integer.toString(hdAccountId)}); + ResultSet c = statement.executeQuery(); + while (c.next()) { + outItems.add(TxHelper.applyCursorOut(c)); + } + + c.close(); + statement.close(); + } catch (AddressFormatException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + return outItems; + } + + @Override + public List getRecentlyTxsByAccount(int hdAccountId, int greateThanBlockNo, int limit) { + List txItemList = new ArrayList(); + String sql = "select distinct a.* " + + " from txs a, addresses_txs b, hd_account_addresses c" + + " where a.tx_hash=b.tx_hash and b.address=c.address " + + " and ((a.block_no is null) or (a.block_no is not null and a.block_no>?)) " + + " and c.hd_account_id=?" + + " order by ifnull(a.block_no,4294967295) desc, a.tx_time desc" + + " limit ?"; +// String sql = "select * from txs where tx_hash in " + +// inQueryTxHashOfHDAccount + +// " and ((block_no is null) or (block_no is not null and block_no>?)) " + +// " order by ifnull(block_no,4294967295) desc, tx_time desc " + +// " limit ? "; + try { + PreparedStatement statement = this.mDb.getPreparedStatement(sql, + new String[]{Integer.toString(greateThanBlockNo) + , Integer.toString(hdAccountId), Integer.toString(limit)}); + ResultSet c = statement.executeQuery(); + while (c.next()) { + Tx txItem = TxHelper.applyCursor(c); + txItemList.add(txItem); + } + + for (Tx item : txItemList) { + TxHelper.addInsAndOuts(mDb, item); + } + c.close(); + statement.close(); + } catch (AddressFormatException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + return txItemList; + } + + + @Override + public int getUnspendOutCountByHDAccountWithPath(int hdAccountId, AbstractHD.PathType pathType) { + int result = 0; + String sql = "select count(tx_hash) cnt from outs where out_address in " + + "(select address from hd_account_addresses where path_type =? and out_status=?) " + + "and hd_account_id=?"; + try { + PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Integer.toString(pathType.getValue()) + , Integer.toString(Out.OutStatus.unspent.getValue()) + , Integer.toString(hdAccountId) + }); + ResultSet c = statement.executeQuery(); + if (c.next()) { + int idColumn = c.findColumn("cnt"); + if (idColumn != -1) { + result = c.getInt(idColumn); + } + } + c.close(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return result; + } + + @Override + public List getUnspendOutByHDAccountWithPath(int hdAccountId, AbstractHD.PathType pathType) { + List outList = new ArrayList(); + + String sql = "select * from outs where out_address in " + + "(select address from hd_account_addresses where path_type =? and out_status=?) " + + "and hd_account_id=?"; + try { + PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Integer.toString(pathType.getValue()) + , Integer.toString(Out.OutStatus.unspent.getValue()) + , Integer.toString(hdAccountId) + }); + ResultSet c = statement.executeQuery(); + while (c.next()) { + outList.add(TxHelper.applyCursorOut(c)); + } + c.close(); + statement.close(); + } catch (AddressFormatException e) { + e.printStackTrace(); + } catch (SQLException e) { + e.printStackTrace(); + } + + return outList; + } + + private HDAccount.HDAccountAddress formatAddress(ResultSet c) throws SQLException { + String address = null; + byte[] pubs = null; + AbstractHD.PathType ternalRootType = AbstractHD.PathType.EXTERNAL_ROOT_PATH; + int index = 0; + boolean isIssued = false; + boolean isSynced = true; + HDAccount.HDAccountAddress hdAccountAddress = null; + try { + int idColumn = c.findColumn(AbstractDb.HDAccountAddressesColumns.ADDRESS); + if (idColumn != -1) { + address = c.getString(idColumn); + } + idColumn = c.findColumn(AbstractDb.HDAccountAddressesColumns.PUB); + if (idColumn != -1) { + pubs = Base58.decode(c.getString(idColumn)); + } + idColumn = c.findColumn(AbstractDb.HDAccountAddressesColumns.PATH_TYPE); + if (idColumn != -1) { + ternalRootType = AbstractHD.getTernalRootType(c.getInt(idColumn)); + + } + idColumn = c.findColumn(AbstractDb.HDAccountAddressesColumns.ADDRESS_INDEX); + if (idColumn != -1) { + index = c.getInt(idColumn); + } + idColumn = c.findColumn(AbstractDb.HDAccountAddressesColumns.IS_ISSUED); + if (idColumn != -1) { + isIssued = c.getInt(idColumn) == 1; + } + idColumn = c.findColumn(AbstractDb.HDAccountAddressesColumns.IS_SYNCED); + if (idColumn != -1) { + isSynced = c.getInt(idColumn) == 1; + } + hdAccountAddress = new HDAccount.HDAccountAddress(address, pubs, + ternalRootType, index, isIssued, isSynced, 0); + } catch (AddressFormatException e) { + e.printStackTrace(); + } + return hdAccountAddress; + } + + private void addAddress(Connection conn, HDAccount.HDAccountAddress accountAddress) throws SQLException { + String sql = "insert into hd_account_addresses(path_type,address_index" + + ",is_issued,address,pub,is_synced) " + + " values(?,?,?,?,?,?)"; + + String[] params = new String[]{Integer.toString(accountAddress.getPathType().getValue()) + , Integer.toString(accountAddress.getIndex()) + , Integer.toString(accountAddress.isIssued() ? 1 : 0) + , accountAddress.getAddress() + , Base58.encode(accountAddress.getPub()) + , Integer.toString(accountAddress.isSyncedComplete() ? 1 : 0) + }; + PreparedStatement stmt = conn.prepareStatement(sql); + if (params != null) { + for (int i = 0; i < params.length; i++) { + stmt.setString(i + 1, params[i]); + } + } + stmt.executeUpdate(); + stmt.close(); + } + + +} diff --git a/src/main/java/net/bither/db/HDAccountProvider.java b/src/main/java/net/bither/db/HDAccountProvider.java index 22e0182..17e13f8 100644 --- a/src/main/java/net/bither/db/HDAccountProvider.java +++ b/src/main/java/net/bither/db/HDAccountProvider.java @@ -1,154 +1,43 @@ -/* - * - * Copyright 2014 http://Bither.net - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - * / - */ - package net.bither.db; import net.bither.ApplicationInstanceManager; -import net.bither.bitherj.BitherjSettings; -import net.bither.bitherj.core.*; +import net.bither.bitherj.core.In; +import net.bither.bitherj.crypto.PasswordSeed; import net.bither.bitherj.db.AbstractDb; import net.bither.bitherj.db.IHDAccountProvider; import net.bither.bitherj.exception.AddressFormatException; import net.bither.bitherj.utils.Base58; -import net.bither.bitherj.utils.Sha256Hash; import net.bither.bitherj.utils.Utils; -import net.bither.utils.StringUtil; -import net.bither.utils.SystemUtil; -import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; public class HDAccountProvider implements IHDAccountProvider { - private final static String queryTxHashOfHDAccount = " select distinct txs.tx_hash from addresses_txs txs ,hd_account_addresses hd where txs.address=hd.address"; - private final static String inQueryTxHashOfHDAccount = " (" + queryTxHashOfHDAccount + ")"; - - - private static HDAccountProvider txProvider = new HDAccountProvider(ApplicationInstanceManager.txDBHelper); + private static HDAccountProvider addressProvider = new HDAccountProvider(ApplicationInstanceManager.addressDBHelper); public static HDAccountProvider getInstance() { - return txProvider; + return addressProvider; } - private TxDBHelper mDb; + private AddressDBHelper mDb; - public HDAccountProvider(TxDBHelper db) { + public HDAccountProvider(AddressDBHelper db) { this.mDb = db; } @Override - public void addAddress(List hdAccountAddresses) { - try { - this.mDb.getConn().setAutoCommit(false); - Connection conn = this.mDb.getConn(); - for (HDAccount.HDAccountAddress hdAccountAddress : hdAccountAddresses) { - addAddress(conn, hdAccountAddress); - } - conn.commit(); - - } catch (SQLException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - - } - - @Override - public int issuedIndex(AbstractHD.PathType pathType) { - int issuedIndex = -1; - try { - PreparedStatement statement = this.mDb.getPreparedStatement("select ifnull(max(address_index),-1) address_index from " + AbstractDb.Tables.HD_ACCOUNT_ADDRESS + " where path_type=? and is_issued=? ", - new String[]{Integer.toString(pathType.getValue()), "1"}); - ResultSet cursor = statement.executeQuery(); - if (cursor.next()) { - int idColumn = cursor.findColumn(AbstractDb.HDAccountAddressesColumns.ADDRESS_INDEX); - if (idColumn != -1) { - issuedIndex = cursor.getInt(idColumn); - } - } - cursor.close(); - statement.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return issuedIndex; - } - - @Override - public int allGeneratedAddressCount(AbstractHD.PathType pathType) { - int count = 0; - try { - PreparedStatement statement = this.mDb.getPreparedStatement("select ifnull(count(address),0) count from " - + AbstractDb.Tables.HD_ACCOUNT_ADDRESS + " where path_type=? ", - new String[]{Integer.toString(pathType.getValue())}); - ResultSet cursor = statement.executeQuery(); - if (cursor.next()) { - int idColumn = cursor.findColumn("count"); - if (idColumn != -1) { - count = cursor.getInt(idColumn); - } - } - cursor.close(); - statement.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return count; - } - - @Override - public void updateIssuedIndex(AbstractHD.PathType pathType, int index) { - String sql = "update hd_account_addresses set is_issued=? where path_type=? and address_index<=? "; - Connection conn = this.mDb.getConn(); - try { - String[] params = new String[]{ - "1", Integer.toString(pathType.getValue()), Integer.toString(index) - }; - PreparedStatement stmt = conn.prepareStatement(sql); - if (params != null) { - for (int i = 0; i < params.length; i++) { - stmt.setString(i + 1, params[i]); - } - } - stmt.executeUpdate(); - conn.commit(); - stmt.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - @Override - public String externalAddress() { + public String getHDFirstAddress(int hdSeedId) { String address = null; try { - PreparedStatement statement = this.mDb.getPreparedStatement("select address from " + AbstractDb.Tables.HD_ACCOUNT_ADDRESS - + " where path_type=? and is_issued=? order by address_index asc limit 1 ", - new String[]{Integer.toString(AbstractHD.PathType.EXTERNAL_ROOT_PATH.getValue()), "0"}); + PreparedStatement statement = this.mDb.getPreparedStatement("select hd_address from hd_account where hd_account_id=?", new String[]{Integer.toString(hdSeedId)}); ResultSet cursor = statement.executeQuery(); if (cursor.next()) { - int idColumn = cursor.findColumn(AbstractDb.HDAccountAddressesColumns.ADDRESS); + int idColumn = cursor.findColumn(AbstractDb.HDAccountColumns.HD_ADDRESS); if (idColumn != -1) { address = cursor.getString(idColumn); } @@ -162,143 +51,86 @@ public String externalAddress() { } @Override - public HashSet getBelongAccountAddresses(List addressList) { - HashSet addressSet = new HashSet(); - - List temp = new ArrayList(); - if (addressList != null) { - for (String str : addressList) { - temp.add(Utils.format("'%s'", str)); - } - } + public int addHDAccount(String encryptedMnemonicSeed, String encryptSeed, String firstAddress + , boolean isXrandom, String addressOfPS, byte[] externalPub + , byte[] internalPub) { + int hdAccountId = -1; try { - String sql = Utils.format("select address from hd_account_addresses where address in (%s) " - , Utils.joinString(temp, ",")); - PreparedStatement statement = this.mDb.getPreparedStatement(sql, - null); - ResultSet cursor = statement.executeQuery(); - while (cursor.next()) { - int idColumn = cursor.findColumn(AbstractDb.HDAccountAddressesColumns.ADDRESS); - if (idColumn != -1) { - addressSet.add(cursor.getString(idColumn)); - } - } - cursor.close(); - statement.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - SystemUtil.maxUsedSize(); - return addressSet; - } - - @Override - public HDAccount.HDAccountAddress addressForPath(AbstractHD.PathType type, int index) { - HDAccount.HDAccountAddress accountAddress = null; - try { - PreparedStatement statement = this.mDb.getPreparedStatement("select address,pub,path_type,address_index,is_issued,is_synced from " + - AbstractDb.Tables.HD_ACCOUNT_ADDRESS + " where path_type=? and address_index=? ", - new String[]{Integer.toString(type.getValue()), Integer.toString(index)}); - ResultSet cursor = statement.executeQuery(); - - if (cursor.next()) { - accountAddress = formatAddress(cursor); - } - cursor.close(); - statement.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return accountAddress; - } - - @Override - public List getPubs(AbstractHD.PathType pathType) { - List adressPubList = new ArrayList(); - try { - PreparedStatement statement = this.mDb.getPreparedStatement("select pub from hd_account_addresses where path_type=? ", - new String[]{Integer.toString(pathType.getValue())}); - ResultSet cursor = statement.executeQuery(); - while (cursor.next()) { - try { - int idColumn = cursor.findColumn(AbstractDb.HDAccountAddressesColumns.PUB); - if (idColumn != -1) { - adressPubList.add(Base58.decode(cursor.getString(idColumn))); - } - } catch (AddressFormatException e) { - e.printStackTrace(); - } - } - cursor.close(); - statement.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return adressPubList; - } - - @Override - public List belongAccount(List addresses) { - List hdAccountAddressList = new ArrayList(); - List temp = new ArrayList(); - for (String str : addresses) { - temp.add(Utils.format("'%s'", str)); - } - String sql = "select address,pub,path_type,address_index,is_issued,is_synced from " + AbstractDb.Tables.HD_ACCOUNT_ADDRESS - + " where address in (" + Utils.joinString(temp, ",") + ")"; - try { - PreparedStatement statement = this.mDb.getPreparedStatement(sql, null); - ResultSet cursor = statement.executeQuery(); - while (cursor.next()) { - hdAccountAddressList.add(formatAddress(cursor)); - + this.mDb.getConn().setAutoCommit(false); + String sql = "insert into hd_account(encrypt_seed,encrypt_mnemonic_seed,is_xrandom,hd_address,external_pub,internal_pub) values(?,?,?,?,?,?);"; + PreparedStatement stmt = this.mDb.getConn().prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + stmt.setString(1, encryptSeed); + stmt.setString(2, encryptedMnemonicSeed); + stmt.setInt(3, isXrandom ? 1 : 0); + stmt.setString(4, firstAddress); + stmt.setString(5, Base58.encode(externalPub)); + stmt.setString(6, Base58.encode(internalPub)); + stmt.executeUpdate(); + if (!AddressProvider.hasPasswordSeed(this.mDb.getConn()) && !Utils.isEmpty(addressOfPS)) { + AddressProvider.addPasswordSeed(this.mDb.getConn(), new PasswordSeed(addressOfPS, encryptedMnemonicSeed)); } - cursor.close(); - statement.close(); + ResultSet tableKeys = stmt.getGeneratedKeys(); + tableKeys.next(); + hdAccountId = tableKeys.getInt(1); + this.mDb.getConn().commit(); + stmt.close(); } catch (SQLException e) { e.printStackTrace(); } - return hdAccountAddressList; + return hdAccountId; } @Override - public void updateSyncdComplete(HDAccount.HDAccountAddress address) { - String sql = "update hd_account_addresses set is_synced=? where address=? "; - Connection conn = this.mDb.getConn(); + public int addMonitoredHDAccount(String firstAddress, boolean isXrandom, byte[] externalPub, byte[] internalPub) { + int hdAccountId = -1; try { - String[] params = new String[]{ - Integer.toString(address.isSyncedComplete() ? 1 : 0), address.getAddress() - }; - PreparedStatement stmt = conn.prepareStatement(sql); - if (params != null) { - for (int i = 0; i < params.length; i++) { - stmt.setString(i + 1, params[i]); - } - } + this.mDb.getConn().setAutoCommit(false); + String sql = "insert into hd_account(is_xrandom,hd_address,external_pub,internal_pub) values(?,?,?,?);"; + PreparedStatement stmt = this.mDb.getConn().prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + stmt.setInt(1, isXrandom ? 1 : 0); + stmt.setString(2, firstAddress); + stmt.setString(3, Base58.encode(externalPub)); + stmt.setString(4, Base58.encode(internalPub)); stmt.executeUpdate(); - conn.commit(); + ResultSet tableKeys = stmt.getGeneratedKeys(); + tableKeys.next(); + hdAccountId = tableKeys.getInt(1); + this.mDb.getConn().commit(); stmt.close(); } catch (SQLException e) { e.printStackTrace(); } + return hdAccountId; } - @Override - public void setSyncdNotComplete() { - this.mDb.executeUpdate("update hd_account_addresses set is_synced=?", new String[]{"0"}); - } +// @Override +// public boolean hasHDAccountCold() { +// boolean result = false; +// SQLiteDatabase db = this.mDb.getReadableDatabase(); +// String sql = "select count(hd_address) cnt from hd_account where encrypt_seed is not " + +// "null and encrypt_mnemonic_seed is not null"; +// Cursor cursor = db.rawQuery(sql, null); +// if (cursor.moveToNext()) { +// int idColumn = cursor.getColumnIndex("cnt"); +// if (idColumn != -1) { +// result = cursor.getInt(idColumn) > 0; +// } +// } +// cursor.close(); +// return result; +// } @Override - public int unSyncedAddressCount() { - int cnt = 0; + public boolean hasMnemonicSeed(int hdAccountId) { + boolean result = false; + String sql = "select count(0) cnt from hd_account where encrypt_mnemonic_seed is not null and hd_account_id=?"; try { - String sql = "select count(address) cnt from hd_account_addresses where is_synced=? "; - PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{"0"}); + PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Integer.toString(hdAccountId)}); ResultSet cursor = statement.executeQuery(); if (cursor.next()) { int idColumn = cursor.findColumn("cnt"); if (idColumn != -1) { - cnt = cursor.getInt(idColumn); + result = cursor.getInt(idColumn) > 0; } } cursor.close(); @@ -306,383 +138,114 @@ public int unSyncedAddressCount() { } catch (SQLException e) { e.printStackTrace(); } - return cnt; - } - - @Override - public void updateSyncdForIndex(AbstractHD.PathType pathType, int index) { - this.mDb.executeUpdate("update hd_account_addresses set is_synced=? where path_type=? and address_index>? " - , new String[]{"1", Integer.toString(pathType.getValue()), Integer.toString(index)}); - - } - - @Override - public List getSigningAddressesForInputs(List inList) { - - List hdAccountAddressList = - new ArrayList(); - ResultSet c; - try { - for (In in : inList) { - String sql = "select a.*" + - " from hd_account_addresses a ,outs b" + - " where a.address=b.out_address" + - " and b.tx_hash=? and b.out_sn=? "; - OutPoint outPoint = in.getOutpoint(); - PreparedStatement statement = this.mDb.getPreparedStatement(sql, - new String[]{Base58.encode(in.getPrevTxHash()), - Integer.toString(outPoint.getOutSn())}); - c = statement.executeQuery(); - if (c.next()) { - hdAccountAddressList.add(formatAddress(c)); - } - c.close(); - statement.close(); - } - } catch (SQLException e) { - e.printStackTrace(); - } - return hdAccountAddressList; + return result; } @Override - public int hdAccountTxCount() { - int result = 0; + public byte[] getExternalPub(int hdSeedId) { + byte[] pub = null; try { - String sql = "select count( distinct a.tx_hash) cnt from addresses_txs a ,hd_account_addresses b where a.address=b.address "; - PreparedStatement statement = this.mDb.getPreparedStatement(sql, null); + PreparedStatement statement = this.mDb.getPreparedStatement("select external_pub from hd_account where hd_account_id=? ", new String[]{Integer.toString(hdSeedId)}); ResultSet c = statement.executeQuery(); if (c.next()) { - int idColumn = c.findColumn("cnt"); + int idColumn = c.findColumn(AbstractDb.HDAccountColumns.EXTERNAL_PUB); if (idColumn != -1) { - result = c.getInt(idColumn); + String pubStr = c.getString(idColumn); + pub = Base58.decode(pubStr); } } c.close(); statement.close(); } catch (SQLException e) { e.printStackTrace(); + } catch (AddressFormatException e) { + e.printStackTrace(); } - return result; + + return pub; } @Override - public long getHDAccountConfirmedBanlance(int hdAccountId) { - long sum = 0; - String unspendOutSql = "select ifnull(sum(a.out_value),0) sum from outs a,txs b where a.tx_hash=b.tx_hash " + - " and a.out_status=? and a.hd_account_id=? and b.block_no is not null"; + public byte[] getInternalPub(int hdSeedId) { + byte[] pub = null; try { - PreparedStatement statement = this.mDb.getPreparedStatement(unspendOutSql, - new String[]{Integer.toString(Out.OutStatus.unspent.getValue()), Integer.toString(hdAccountId)}); + PreparedStatement statement = this.mDb.getPreparedStatement("select internal_pub from hd_account where hd_account_id=? ", new String[]{Integer.toString(hdSeedId)}); ResultSet c = statement.executeQuery(); if (c.next()) { - int idColumn = c.findColumn("sum"); + int idColumn = c.findColumn(AbstractDb.HDAccountColumns.INTERNAL_PUB); if (idColumn != -1) { - sum = c.getLong(idColumn); + String pubStr = c.getString(idColumn); + pub = Base58.decode(pubStr); } } c.close(); statement.close(); } catch (SQLException e) { e.printStackTrace(); - } - return sum; - } - - @Override - public List getHDAccountUnconfirmedTx() { - List txList = new ArrayList(); - - HashMap txDict = new HashMap(); - - try { - String sql = "select * from txs where tx_hash in" + - inQueryTxHashOfHDAccount + - " and block_no is null " + - " order by block_no desc"; - PreparedStatement statement = this.mDb.getPreparedStatement(sql, null); - ResultSet c = statement.executeQuery(); - while (c.next()) { - Tx txItem = TxHelper.applyCursor(c); - txItem.setIns(new ArrayList()); - txItem.setOuts(new ArrayList()); - txList.add(txItem); - txDict.put(new Sha256Hash(txItem.getTxHash()), txItem); - } - c.close(); - statement.close(); - sql = "select b.* " + - " from ins b, txs c " + - " where c.tx_hash in " + - inQueryTxHashOfHDAccount + - " and b.tx_hash=c.tx_hash and c.block_no is null " + - " order by b.tx_hash ,b.in_sn"; - statement = this.mDb.getPreparedStatement(sql, null); - c = statement.executeQuery(); - while (c.next()) { - In inItem = TxHelper.applyCursorIn(c); - Tx tx = txDict.get(new Sha256Hash(inItem.getTxHash())); - if (tx != null) { - tx.getIns().add(inItem); - } - } - c.close(); - statement.close(); - - sql = "select b.* " + - " from outs b, txs c " + - " where c.tx_hash in" + - inQueryTxHashOfHDAccount + - " and b.tx_hash=c.tx_hash and c.block_no is null " + - " order by b.tx_hash,b.out_sn"; - statement = this.mDb.getPreparedStatement(sql, null); - c = statement.executeQuery(); - while (c.next()) { - Out out = TxHelper.applyCursorOut(c); - Tx tx = txDict.get(new Sha256Hash(out.getTxHash())); - if (tx != null) { - tx.getOuts().add(out); - } - } - c.close(); - statement.close(); - } catch (AddressFormatException e) { e.printStackTrace(); - } catch (SQLException e) { - e.printStackTrace(); } - return txList; - } - - @Override - public long sentFromAccount(int hdAccountId, byte[] txHash) { - String sql = "select sum(o.out_value) out_value from ins i,outs o where" + - " i.tx_hash=? and o.tx_hash=i.prev_tx_hash and i.prev_out_sn=o.out_sn and o.hd_account_id=?"; - long sum = 0; - - ResultSet cursor; - try { - PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Base58.encode(txHash), - Integer.toString(hdAccountId)}); - cursor = statement.executeQuery(); - if (cursor.next()) { - int idColumn = cursor.findColumn(AbstractDb.OutsColumns.OUT_VALUE); - if (idColumn != -1) { - sum = cursor.getLong(idColumn); - } - } - cursor.close(); - statement.close(); - } catch (SQLException e) { - e.printStackTrace(); - } - return sum; + return pub; } - @Override - public List getTxAndDetailByHDAccount() { - List txItemList = new ArrayList(); - - HashMap txDict = new HashMap(); - - try { - String sql = "select * from txs where tx_hash in " + - inQueryTxHashOfHDAccount + - " order by" + - " ifnull(block_no,4294967295) desc "; - PreparedStatement statement = this.mDb.getPreparedStatement(sql, null); - ResultSet c = statement.executeQuery(); - StringBuilder txsStrBuilder = new StringBuilder(); - while (c.next()) { - Tx txItem = TxHelper.applyCursor(c); - txItem.setIns(new ArrayList()); - txItem.setOuts(new ArrayList()); - txItemList.add(txItem); - txDict.put(new Sha256Hash(txItem.getTxHash()), txItem); - txsStrBuilder.append("'").append(Base58.encode(txItem.getTxHash())).append("'").append(","); - } - c.close(); - statement.close(); - - if (txsStrBuilder.length() > 1) { - String txs = txsStrBuilder.substring(0, txsStrBuilder.length() - 1); - sql = Utils.format("select b.* from ins b where b.tx_hash in (%s)" + - " order by b.tx_hash ,b.in_sn", txs); - statement = this.mDb.getPreparedStatement(sql, null); - c = statement.executeQuery(); - while (c.next()) { - In inItem = TxHelper.applyCursorIn(c); - Tx tx = txDict.get(new Sha256Hash(inItem.getTxHash())); - if (tx != null) { - tx.getIns().add(inItem); - } - } - c.close(); - statement.close(); - - sql = Utils.format("select b.* from outs b where b.tx_hash in (%s)" + - " order by b.tx_hash,b.out_sn", txs); - statement = this.mDb.getPreparedStatement(sql, null); - c = statement.executeQuery(); - while (c.next()) { - Out out = TxHelper.applyCursorOut(c); - Tx tx = txDict.get(new Sha256Hash(out.getTxHash())); - if (tx != null) { - tx.getOuts().add(out); - } - } - c.close(); - statement.close(); - } - } catch (AddressFormatException e) { - e.printStackTrace(); - } catch (SQLException e) { - e.printStackTrace(); - } - return txItemList; - } @Override - public List getTxAndDetailByHDAccount(int page) { - List txItemList = new ArrayList(); - - HashMap txDict = new HashMap(); - + public String getHDAccountEncryptSeed(int hdSeedId) { + String hdAccountEncryptSeed = null; try { - String sql = "select * from txs where tx_hash in " + - inQueryTxHashOfHDAccount + - " order by" + - " ifnull(block_no,4294967295) desc limit ?,? "; - PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{ - Integer.toString((page - 1) * BitherjSettings.TX_PAGE_SIZE), Integer.toString(BitherjSettings.TX_PAGE_SIZE) - }); + PreparedStatement statement = this.mDb.getPreparedStatement("select " + AbstractDb.HDAccountColumns.ENCRYPT_SEED + " from hd_account where hd_account_id=? ", new String[]{Integer.toString(hdSeedId)}); ResultSet c = statement.executeQuery(); - StringBuilder txsStrBuilder = new StringBuilder(); - while (c.next()) { - Tx txItem = TxHelper.applyCursor(c); - txItem.setIns(new ArrayList()); - txItem.setOuts(new ArrayList()); - txItemList.add(txItem); - txDict.put(new Sha256Hash(txItem.getTxHash()), txItem); - txsStrBuilder.append("'").append(Base58.encode(txItem.getTxHash())).append("'").append(","); - } - c.close(); - statement.close(); - - if (txsStrBuilder.length() > 1) { - String txs = txsStrBuilder.substring(0, txsStrBuilder.length() - 1); - sql = Utils.format("select b.* from ins b where b.tx_hash in (%s)" + - " order by b.tx_hash ,b.in_sn", txs); - statement = this.mDb.getPreparedStatement(sql, null); - c = statement.executeQuery(); - while (c.next()) { - In inItem = TxHelper.applyCursorIn(c); - Tx tx = txDict.get(new Sha256Hash(inItem.getTxHash())); - if (tx != null) { - tx.getIns().add(inItem); - } - } - c.close(); - statement.close(); - - sql = Utils.format("select b.* from outs b where b.tx_hash in (%s)" + - " order by b.tx_hash,b.out_sn", txs); - statement = this.mDb.getPreparedStatement(sql, null); - c = statement.executeQuery(); - while (c.next()) { - Out out = TxHelper.applyCursorOut(c); - Tx tx = txDict.get(new Sha256Hash(out.getTxHash())); - if (tx != null) { - tx.getOuts().add(out); - } + if (c.next()) { + int idColumn = c.findColumn(AbstractDb.HDAccountColumns.ENCRYPT_SEED); + if (idColumn != -1) { + hdAccountEncryptSeed = c.getString(idColumn); } - c.close(); - statement.close(); - } - } catch (AddressFormatException e) { - e.printStackTrace(); - } catch (SQLException e) { - e.printStackTrace(); - } - return txItemList; - } - - @Override - public List getUnspendOutByHDAccount(int hdAccountId) { - List outItems = new ArrayList(); - String unspendOutSql = "select a.* from outs a,txs b where a.tx_hash=b.tx_hash " + - " and a.out_status=? and a.hd_account_id=?"; - try { - PreparedStatement statement = this.mDb.getPreparedStatement(unspendOutSql, - new String[]{Integer.toString(Out.OutStatus.unspent.getValue()), Integer.toString(hdAccountId)}); - ResultSet c = statement.executeQuery(); - while (c.next()) { - outItems.add(TxHelper.applyCursorOut(c)); - } - c.close(); statement.close(); - } catch (AddressFormatException e) { - e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } - return outItems; + + return hdAccountEncryptSeed; } @Override - public List getRecentlyTxsByAccount(int greateThanBlockNo, int limit) { - List txItemList = new ArrayList(); + public String getHDAccountEncryptMnemonicSeed(int hdSeedId) { + String hdAccountMnmonicEncryptSeed = null; - String sql = "select * from txs where tx_hash in " + - inQueryTxHashOfHDAccount + - " and ((block_no is null) or (block_no is not null and block_no>?)) " + - " order by ifnull(block_no,4294967295) desc, tx_time desc " + - " limit ? "; try { - PreparedStatement statement = this.mDb.getPreparedStatement(sql, - new String[]{Integer.toString(greateThanBlockNo), Integer.toString(limit)}); + PreparedStatement statement = this.mDb.getPreparedStatement("select " + AbstractDb.HDAccountColumns.ENCRYPT_MNMONIC_SEED + " from hd_account where hd_account_id=? ", new String[]{Integer.toString(hdSeedId)}); ResultSet c = statement.executeQuery(); - while (c.next()) { - Tx txItem = TxHelper.applyCursor(c); - txItemList.add(txItem); - } - - for (Tx item : txItemList) { - TxHelper.addInsAndOuts(mDb, item); + if (c.next()) { + int idColumn = c.findColumn(AbstractDb.HDAccountColumns.ENCRYPT_MNMONIC_SEED); + if (idColumn != -1) { + hdAccountMnmonicEncryptSeed = c.getString(idColumn); + } } c.close(); statement.close(); - } catch (AddressFormatException e) { - e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } - return txItemList; - } + return hdAccountMnmonicEncryptSeed; + } @Override - public int getUnspendOutCountByHDAccountWithPath(int hdAccountId, AbstractHD.PathType pathType) { - int result = 0; - String sql = "select count(tx_hash) cnt from outs where out_address in " + - "(select address from hd_account_addresses where path_type =? and out_status=?) " + - "and hd_account_id=?"; + public boolean hdAccountIsXRandom(int seedId) { + boolean result = false; + try { - PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Integer.toString(pathType.getValue()) - , Integer.toString(Out.OutStatus.unspent.getValue()) - , Integer.toString(hdAccountId) - }); + PreparedStatement statement = this.mDb.getPreparedStatement("select is_xrandom from hd_account where hd_account_id=?", new String[]{Integer.toString(seedId)}); ResultSet c = statement.executeQuery(); if (c.next()) { - int idColumn = c.findColumn("cnt"); + int idColumn = c.findColumn(AbstractDb.HDAccountColumns.ENCRYPT_MNMONIC_SEED); if (idColumn != -1) { - result = c.getInt(idColumn); + result = c.getInt(idColumn) == 1; } } c.close(); @@ -694,95 +257,24 @@ public int getUnspendOutCountByHDAccountWithPath(int hdAccountId, AbstractHD.Pat } @Override - public List getUnspendOutByHDAccountWithPath(int hdAccountId, AbstractHD.PathType pathType) { - List outList = new ArrayList(); - - String sql = "select * from outs where out_address in " + - "(select address from hd_account_addresses where path_type =? and out_status=?) " + - "and hd_account_id=?"; + public List getHDAccountSeeds() { + List hdSeedIds = new ArrayList(); try { - PreparedStatement statement = this.mDb.getPreparedStatement(sql, new String[]{Integer.toString(pathType.getValue()) - , Integer.toString(Out.OutStatus.unspent.getValue()) - , Integer.toString(hdAccountId) - }); + PreparedStatement statement = this.mDb.getPreparedStatement("select " + AbstractDb.HDAccountColumns.HD_ACCOUNT_ID + " from " + AbstractDb.Tables.HD_ACCOUNT, null); ResultSet c = statement.executeQuery(); while (c.next()) { - outList.add(TxHelper.applyCursorOut(c)); + hdSeedIds.add(c.getInt(1)); } c.close(); statement.close(); - } catch (AddressFormatException e) { - e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } - - return outList; + return hdSeedIds; } - private HDAccount.HDAccountAddress formatAddress(ResultSet c) throws SQLException { - String address = null; - byte[] pubs = null; - AbstractHD.PathType ternalRootType = AbstractHD.PathType.EXTERNAL_ROOT_PATH; - int index = 0; - boolean isIssued = false; - boolean isSynced = true; - HDAccount.HDAccountAddress hdAccountAddress = null; - try { - int idColumn = c.findColumn(AbstractDb.HDAccountAddressesColumns.ADDRESS); - if (idColumn != -1) { - address = c.getString(idColumn); - } - idColumn = c.findColumn(AbstractDb.HDAccountAddressesColumns.PUB); - if (idColumn != -1) { - pubs = Base58.decode(c.getString(idColumn)); - } - idColumn = c.findColumn(AbstractDb.HDAccountAddressesColumns.PATH_TYPE); - if (idColumn != -1) { - ternalRootType = AbstractHD.getTernalRootType(c.getInt(idColumn)); - - } - idColumn = c.findColumn(AbstractDb.HDAccountAddressesColumns.ADDRESS_INDEX); - if (idColumn != -1) { - index = c.getInt(idColumn); - } - idColumn = c.findColumn(AbstractDb.HDAccountAddressesColumns.IS_ISSUED); - if (idColumn != -1) { - isIssued = c.getInt(idColumn) == 1; - } - idColumn = c.findColumn(AbstractDb.HDAccountAddressesColumns.IS_SYNCED); - if (idColumn != -1) { - isSynced = c.getInt(idColumn) == 1; - } - hdAccountAddress = new HDAccount.HDAccountAddress(address, pubs, - ternalRootType, index, isIssued, isSynced); - } catch (AddressFormatException e) { - e.printStackTrace(); - } - return hdAccountAddress; - } - - private void addAddress(Connection conn, HDAccount.HDAccountAddress accountAddress) throws SQLException { - String sql = "insert into hd_account_addresses(path_type,address_index" + - ",is_issued,address,pub,is_synced) " + - " values(?,?,?,?,?,?)"; - - String[] params = new String[]{Integer.toString(accountAddress.getPathType().getValue()) - , Integer.toString(accountAddress.getIndex()) - , Integer.toString(accountAddress.isIssued() ? 1 : 0) - , accountAddress.getAddress() - , Base58.encode(accountAddress.getPub()) - , Integer.toString(accountAddress.isSyncedComplete() ? 1 : 0) - }; - PreparedStatement stmt = conn.prepareStatement(sql); - if (params != null) { - for (int i = 0; i < params.length; i++) { - stmt.setString(i + 1, params[i]); - } - } - stmt.executeUpdate(); - stmt.close(); + @Override + public boolean isPubExist(byte[] externalPub, byte[] internalPub) { + return false; } - - } diff --git a/src/main/java/net/bither/db/Peer2Provider.java b/src/main/java/net/bither/db/Peer2Provider.java new file mode 100644 index 0000000..56db6b9 --- /dev/null +++ b/src/main/java/net/bither/db/Peer2Provider.java @@ -0,0 +1,99 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.db; + +import net.bither.ApplicationInstanceManager; +import net.bither.bitherj.core.Peer; +import net.bither.bitherj.db.imp.AbstractPeerProvider; +import net.bither.bitherj.db.imp.base.IDb; +import net.bither.bitherj.utils.Utils; +import net.bither.db.base.JavaDb; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class Peer2Provider extends AbstractPeerProvider { + + private static Peer2Provider peerProvider = new Peer2Provider(ApplicationInstanceManager.txDBHelper); + + public static Peer2Provider getInstance() { + return peerProvider; + } + + private TxDBHelper helper; + + public Peer2Provider(TxDBHelper helper) { + this.helper = helper; + } + + @Override + public IDb getReadDb() { + return new JavaDb(this.helper.getConn()); + } + + @Override + public IDb getWriteDb() { + return new JavaDb(this.helper.getConn()); + } + +// @Override +// public void addPeers(List items) { +// List addItems = new ArrayList(); +// List allItems = getAllPeers(); +// for (Peer peerItem : items) { +// if (!allItems.contains(peerItem) && !addItems.contains(peerItem)) { +// addItems.add(peerItem); +// } +// } +// if (addItems.size() > 0) { +// String sql = "insert into peers(peer_address,peer_port,peer_services,peer_timestamp,peer_connected_cnt) values(?,?,?,?,?)"; +// IDb writeDb = this.getWriteDb(); +// writeDb.beginTransaction(); +// for (Peer item : addItems) { +// try { +// PreparedStatement statement = ((JavaDb)this.getWriteDb()).getConnection().prepareStatement(sql); +// statement.setLong(1, Utils.parseLongFromAddress(item.getPeerAddress())); +// statement.setString(2, "8333"); +// statement.setLong(3, item.getPeerServices()); +// statement.setLong(4, item.getPeerTimestamp()); +// statement.setInt(5, item.getPeerConnectedCnt()); +//// if (params != null && params.length > 0) { +//// for (int i = 1; i <= params.length; i++) { +//// statement.setString(1, params[i - 1]); +//// } +//// } +// statement.executeUpdate(); +// statement.close(); +// } catch (SQLException e) { +// +// } +// +//// this.execUpdate(writeDb, sql, new String[]{ +//// Long.toString(Utils.parseLongFromAddress(item.getPeerAddress())) +//// , Integer.toString(item.getPeerPort()) +//// , Long.toString(item.getPeerServices()) +//// , Integer.toString(item.getPeerTimestamp()) +//// , Integer.toString(item.getPeerConnectedCnt())}); +// } +// writeDb.endTransaction(); +// } +// } +} diff --git a/src/main/java/net/bither/db/Tx2Provider.java b/src/main/java/net/bither/db/Tx2Provider.java new file mode 100644 index 0000000..bc7e6ab --- /dev/null +++ b/src/main/java/net/bither/db/Tx2Provider.java @@ -0,0 +1,118 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.db; + +import com.google.common.base.Function; +import net.bither.ApplicationInstanceManager; +import net.bither.bitherj.core.In; +import net.bither.bitherj.core.Out; +import net.bither.bitherj.core.Tx; +import net.bither.bitherj.db.imp.AbstractTxProvider; +import net.bither.bitherj.db.imp.base.ICursor; +import net.bither.bitherj.db.imp.base.IDb; +import net.bither.bitherj.utils.Base58; +import net.bither.bitherj.utils.Utils; +import net.bither.db.base.JavaCursor; +import net.bither.db.base.JavaDb; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class Tx2Provider extends AbstractTxProvider { + + private static Tx2Provider txProvider = new Tx2Provider(ApplicationInstanceManager.txDBHelper); + + public static Tx2Provider getInstance() { + return txProvider; + } + + private TxDBHelper helper; + + public Tx2Provider(TxDBHelper helper) { + this.helper = helper; + } + + @Override + public IDb getReadDb() { + return new JavaDb(this.helper.getConn()); + } + + @Override + public IDb getWriteDb() { + return new JavaDb(this.helper.getConn()); + } + + String txInsertSql = "insert into txs " + + "(tx_hash,tx_ver,tx_locktime,tx_time,block_no,source)" + + " values (?,?,?,?,?,?) "; + String inInsertSql = "insert into ins " + + "(tx_hash,in_sn,prev_tx_hash,prev_out_sn,in_signature,in_sequence)" + + " values (?,?,?,?,?,?) "; + String outInsertSql = "insert into outs " + + "(tx_hash,out_sn,out_script,out_value,out_status,out_address,hd_account_id)" + + " values (?,?,?,?,?,?,?)"; + + @Override + protected void insertTxToDb(IDb db, Tx tx) { + String blockNoString = null; + if (tx.getBlockNo() != Tx.TX_UNCONFIRMED) { + blockNoString = Integer.toString(tx.getBlockNo()); + } + this.execUpdate(db, txInsertSql, new String[] { + Base58.encode(tx.getTxHash()), + Long.toString(tx.getTxVer()), + Long.toString(tx.getTxLockTime()), + Long.toString(tx.getTxTime()), + blockNoString, + Integer.toString(tx.getSource()) + }); + } + + @Override + protected void insertInToDb(IDb db, In in) { + String signatureString = null; + if (in.getInSignature() != null) { + signatureString = Base58.encode(in.getInSignature()); + } + this.execUpdate(db, inInsertSql, new String[]{ + Base58.encode(in.getTxHash()), + Integer.toString(in.getInSn()), + Base58.encode(in.getPrevTxHash()), + Integer.toString(in.getPrevOutSn()), + signatureString, + Long.toString(in.getInSequence()) + }); + } + + @Override + protected void insertOutToDb(IDb db, Out out) { + String outAddress = null; + if (!Utils.isEmpty(out.getOutAddress())) { + outAddress = out.getOutAddress(); + } + this.execUpdate(db, outInsertSql, new String[] {Base58.encode(out.getTxHash()) + , Integer.toString(out.getOutSn()) + , Base58.encode(out.getOutScript()) + , Long.toString(out.getOutValue()) + , Integer.toString(out.getOutStatus().getValue()) + , outAddress + , Integer.toString(out.getHDAccountId())}); + } +} diff --git a/src/main/java/net/bither/db/TxDBHelper.java b/src/main/java/net/bither/db/TxDBHelper.java index e75992c..3630bb6 100644 --- a/src/main/java/net/bither/db/TxDBHelper.java +++ b/src/main/java/net/bither/db/TxDBHelper.java @@ -18,6 +18,7 @@ package net.bither.db; +import net.bither.ApplicationInstanceManager; import net.bither.bitherj.db.AbstractDb; import net.bither.preference.UserPreference; @@ -29,7 +30,20 @@ public class TxDBHelper extends AbstractDBHelper { private static final String DB_NAME = "bither.db"; - private static final int CURRENT_VERSION = 2; + private static final int CURRENT_VERSION = 3; + + public static final String CREATE_ENTERPRISE_HDM_ADDRESSES = "create table if not exists desktop_hdm_account_addresses " + + "(path_type integer not null" + + ", address_index integer not null" + + ", is_issued integer not null" + + ", address text not null" + + ", pub_key_1 text not null" + + ", pub_key_2 text not null" + + ", pub_key_3 text not null" + + ", is_synced integer not null" + + ", primary key (address));"; + + public static final String ADD_ENTERPRISE_HD_ACCOUNT_ID_FOR_OUTS = "alter table outs add column enterprise_hd_account_id integer;"; public TxDBHelper(String dbDir) { super(dbDir); @@ -69,6 +83,9 @@ protected void onUpgrade(Connection conn, int newVersion, int oldVerion) throws switch (oldVerion) { case 1: v1ToV2(stmt); + case 2: + v2Tov3(stmt); + } conn.commit(); stmt.close(); @@ -93,6 +110,9 @@ protected void onCreate(Connection conn) throws SQLException { createHDAccountAddress(stmt); + stmt.executeUpdate(CREATE_ENTERPRISE_HDM_ADDRESSES); + stmt.executeUpdate(ADD_ENTERPRISE_HD_ACCOUNT_ID_FOR_OUTS); + conn.commit(); stmt.close(); UserPreference.getInstance().setTxDbVersion(CURRENT_VERSION); @@ -136,11 +156,77 @@ private void createHDAccountAddress(Statement stmt) throws SQLException { private void v1ToV2(Statement stmt) throws SQLException { stmt.executeUpdate(AbstractDb.ADD_HD_ACCOUNT_ID_FOR_OUTS); - createHDAccountAddress(stmt); } + private void v2Tov3(Statement statement) throws SQLException { + statement.executeUpdate(CREATE_ENTERPRISE_HDM_ADDRESSES); + statement.executeUpdate(ADD_ENTERPRISE_HD_ACCOUNT_ID_FOR_OUTS); + + // add hd_account_id to hd_account_addresses + ResultSet c = statement.executeQuery("select count(0) from hd_account_addresses"); + int cnt = 0; + if (c.next()) { + cnt = c.getInt(0); + } + c.close(); + + statement.execute("create table if not exists " + + "hd_account_addresses2 " + + "(hd_account_id integer not null" + + ", path_type integer not null" + + ", address_index integer not null" + + ", is_issued integer not null" + + ", address text not null" + + ", pub text not null" + + ", is_synced integer not null" + + ", primary key (address));"); + if (cnt > 0) { + statement.execute("ALTER TABLE hd_account_addresses ADD COLUMN hd_account_id integer"); + + int hd_account_id = -1; + c = ApplicationInstanceManager.addressDBHelper.getConn().createStatement().executeQuery("select hd_account_id from hd_account"); + if (c.next()) { + hd_account_id = c.getInt(0); + if (c.next()) { + c.close(); + throw new RuntimeException("tx db upgrade from 2 to 3 failed. more than one record in hd_account"); + } else { + c.close(); + } + } else { + c.close(); + throw new RuntimeException("tx db upgrade from 2 to 3 failed. no record in hd_account"); + } + + statement.execute("update hd_account_addresses set hd_account_id=?", new String[] {Integer.toString(hd_account_id)}); + statement.execute("INSERT INTO hd_account_addresses2(hd_account_id,path_type,address_index,is_issued,address,pub,is_synced) " + + "SELECT hd_account_id,path_type,address_index,is_issued,address,pub,is_synced FROM hd_account_addresses;"); + } + int oldCnt = 0; + int newCnt = 0; + c = statement.executeQuery("select count(0) cnt from hd_account_addresses"); + if (c.next()) { + oldCnt = c.getInt(0); + } + c.close(); + c = statement.executeQuery("select count(0) cnt from hd_account_addresses2"); + if (c.next()) { + newCnt = c.getInt(0); + } + c.close(); + if (oldCnt != newCnt) { + throw new RuntimeException("tx db upgrade from 2 to 3 failed. new hd_account_addresses table record count not the same as old one"); + } else { + statement.execute("DROP TABLE hd_account_addresses;"); + statement.execute("ALTER TABLE hd_account_addresses2 RENAME TO hd_account_addresses;"); + } + + statement.execute(AbstractDb.CREATE_OUT_HD_ACCOUNT_ID_INDEX); + statement.execute(AbstractDb.CREATE_HD_ACCOUNT_ACCOUNT_ID_AND_PATH_TYPE_INDEX); + } + public void rebuildTx() { try { getConn().setAutoCommit(false); @@ -158,6 +244,7 @@ public void rebuildTx() { stmt.executeUpdate(AbstractDb.CREATE_INS_SQL); stmt.executeUpdate(AbstractDb.CREATE_ADDRESSTXS_SQL); stmt.executeUpdate(AbstractDb.CREATE_PEER_SQL); + stmt.executeUpdate(ADD_ENTERPRISE_HD_ACCOUNT_ID_FOR_OUTS); getConn().commit(); stmt.close(); diff --git a/src/main/java/net/bither/db/TxProvider.java b/src/main/java/net/bither/db/TxProvider.java index 81ef3d1..8104f44 100644 --- a/src/main/java/net/bither/db/TxProvider.java +++ b/src/main/java/net/bither/db/TxProvider.java @@ -18,10 +18,7 @@ import net.bither.ApplicationInstanceManager; import net.bither.bitherj.BitherjSettings; -import net.bither.bitherj.core.AddressManager; -import net.bither.bitherj.core.In; -import net.bither.bitherj.core.Out; -import net.bither.bitherj.core.Tx; +import net.bither.bitherj.core.*; import net.bither.bitherj.db.AbstractDb; import net.bither.bitherj.db.ITxProvider; import net.bither.bitherj.exception.AddressFormatException; @@ -45,8 +42,8 @@ public class TxProvider implements ITxProvider { " values (?,?,?,?,?,?) "; String outInsertSql = "insert into outs " + - "(tx_hash,out_sn,out_script,out_value,out_status,out_address,hd_account_id)" + - " values (?,?,?,?,?,?,?) "; + "(tx_hash,out_sn,out_script,out_value,out_status,out_address,hd_account_id,enterprise_hd_account_id)" + + " values (?,?,?,?,?,?,?,?) "; private static TxProvider txProvider = new TxProvider(ApplicationInstanceManager.txDBHelper); @@ -340,13 +337,25 @@ public void addTxs(List txItems) { } private void addTxToDb(Connection conn, Tx txItem) throws SQLException { - HashSet addressSet = AbstractDb.hdAccountProvider. - getBelongAccountAddresses(txItem.getOutAddressList()); - for (Out out : txItem.getOuts()) { - if (addressSet.contains(out.getOutAddress())) { - out.setHDAccountId(AddressManager.getInstance().getHdAccount().getHdSeedId()); - } - } +// HashSet addressSet = AbstractDb.hdAccountProvider. +// getBelongAccountAddresses(txItem.getOutAddressList()); +// for (Out out : txItem.getOuts()) { +// if (addressSet.contains(out.getOutAddress())) { +// out.setHDAccountId(AddressManager.getInstance().getHdAccount().getHdSeedId()); +// } +// } +// +// +// if (AddressManager.getInstance().hasDesktopHDMKeychain()) { +// DesktopHDMKeychain desktopHDMKeychain = AddressManager.getInstance().getDesktopHDMKeychains().get(0); +// HashSet desktophdmAddressSet = AbstractDb.desktopTxProvider. +// getBelongAccountAddresses(txItem.getOutAddressList()); +// for (Out out : txItem.getOuts()) { +// if (desktophdmAddressSet.contains(out.getOutAddress())) { +// out.setDesktopHDMAccountId(desktopHDMKeychain.getHdSeedId()); +// } +// } +// } insertTx(conn, txItem); List addressesTxsRels = new ArrayList(); List temp = insertIn(conn, txItem); @@ -370,7 +379,7 @@ private void addTxToDb(Connection conn, Tx txItem) throws SQLException { } - private void insertTx(Connection conn, Tx txItem) throws SQLException { + private void insertTx(Connection conn, Tx txItem) throws SQLException { String existSql = "select count(0) cnt from txs where tx_hash=?"; PreparedStatement preparedStatement = conn.prepareStatement(existSql); preparedStatement.setString(1, Base58.encode(txItem.getTxHash())); @@ -436,6 +445,7 @@ private List insertOut(Connection conn, Tx txItem) throws SQLExceptio preparedStatement.setInt(5, outItem.getOutStatus().getValue()); preparedStatement.setString(6, outAddress); preparedStatement.setInt(7, outItem.getHDAccountId()); + preparedStatement.setInt(8, outItem.getDesktopHDMAccountId()); preparedStatement.executeUpdate(); preparedStatement.close(); } else { @@ -447,6 +457,14 @@ private List insertOut(Connection conn, Tx txItem) throws SQLExceptio preparedStatement.executeUpdate(); preparedStatement.close(); } + if (outItem.getDesktopHDMAccountId() > -1) { + preparedStatement = conn.prepareStatement("update outs set enterprise_hd_account_id=? where tx_hash=? and out_sn=?"); + preparedStatement.setString(1, Integer.toString(outItem.getDesktopHDMAccountId())); + preparedStatement.setString(2, Base58.encode(txItem.getTxHash())); + preparedStatement.setString(3, Integer.toString(outItem.getOutSn())); + preparedStatement.executeUpdate(); + preparedStatement.close(); + } } if (!Utils.isEmpty(outItem.getOutAddress())) { addressTxes.add(new AddressTx(outItem.getOutAddress(), Base58.encode(txItem.getTxHash()))); diff --git a/src/main/java/net/bither/db/base/JavaCursor.java b/src/main/java/net/bither/db/base/JavaCursor.java new file mode 100644 index 0000000..ec9f615 --- /dev/null +++ b/src/main/java/net/bither/db/base/JavaCursor.java @@ -0,0 +1,254 @@ +package net.bither.db.base; + +import net.bither.bitherj.db.imp.base.ICursor; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class JavaCursor implements ICursor { + private ResultSet rs; + + public JavaCursor(ResultSet rs) { + this.rs = rs; + } + + @Override + public int getCount() { + try { + return rs.getRow(); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public boolean move(int var1) { + try { + return rs.absolute(var1); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean moveToPosition(int var1) { + try { + return rs.absolute(var1); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean moveToFirst() { + try { + return rs.first(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean moveToLast() { + try { + return rs.last(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean moveToNext() { + try { + return rs.next(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean moveToPrevious() { + try { + return rs.previous(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean isFirst() { + try { + return rs.isFirst(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean isLast() { + try { + return rs.isLast(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean isBeforeFirst() { + try { + return rs.isBeforeFirst(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean isAfterLast() { + try { + return rs.isAfterLast(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public int getColumnIndex(String var1) { + try { + return rs.findColumn(var1) - 1; + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public int getColumnIndexOrThrow(String var1) throws IllegalArgumentException { + try { + return rs.findColumn(var1); + } catch (SQLException e) { + e.printStackTrace(); + throw new IllegalArgumentException(e); + } + } + + @Override + public byte[] getBlob(int var1) { + try { + return rs.getBytes(var1 + 1); + } catch (SQLException e) { + e.printStackTrace(); + return new byte[0]; + } + } + + @Override + public String getString(int var1) { + try { + return rs.getString(var1 + 1); + } catch (SQLException e) { + e.printStackTrace(); + return null; + } + } + + @Override + public short getShort(int var1) { + try { + return rs.getShort(var1 + 1); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public int getInt(int var1) { + try { + return rs.getInt(var1 + 1); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public long getLong(int var1) { + try { + return rs.getLong(var1 + 1); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public float getFloat(int var1) { + try { + return rs.getFloat(var1 + 1); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public double getDouble(int var1) { + try { + return rs.getDouble(var1 + 1); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public int getType(int var1) { + try { + return rs.getType(); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public boolean isNull(int var1) { + try { + rs.getObject(var1 + 1); + return rs.wasNull(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public void close() { + try { + rs.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public boolean isClosed() { + try { + return rs.isClosed(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } +} diff --git a/src/main/java/net/bither/db/base/JavaDb.java b/src/main/java/net/bither/db/base/JavaDb.java new file mode 100644 index 0000000..b9ef689 --- /dev/null +++ b/src/main/java/net/bither/db/base/JavaDb.java @@ -0,0 +1,105 @@ +package net.bither.db.base; + +import com.google.common.base.Function; +import net.bither.bitherj.db.imp.base.ICursor; +import net.bither.bitherj.db.imp.base.IDb; +import net.bither.db.AbstractDBHelper; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class JavaDb implements IDb { + private Connection connection; + + public JavaDb(Connection connection) { + this.connection = connection; + } + + @Override + public void beginTransaction() { + try { + this.connection.setAutoCommit(false); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public void endTransaction() { + try { + this.connection.commit(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public void close() { + try { + this.connection.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public void execUpdate(String sql, String[] params) { + try { + PreparedStatement statement = this.getConnection().prepareStatement(sql); + if (params != null && params.length > 0) { + for (int i = 1; i <= params.length; i++) { + statement.setString(i, params[i - 1]); + } + } + statement.executeUpdate(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public void execQueryOneRecord(String sql, String[] params, Function func) { + try { + PreparedStatement preparedStatement = this.getConnection().prepareStatement(sql); + if (params != null && params.length > 0) { + for (int i = 1; i <= params.length; i++) { + preparedStatement.setString(i, params[i - 1]); + } + } + ICursor c = new JavaCursor(preparedStatement.executeQuery()); + if (c.moveToNext()) { + func.apply(c); + } + c.close(); + preparedStatement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public void execQueryLoop(String sql, String[] params, Function func) { + try { + PreparedStatement preparedStatement = this.getConnection().prepareStatement(sql); + if (params != null && params.length > 0) { + for (int i = 1; i <= params.length; i++) { + preparedStatement.setString(i, params[i - 1]); + } + } + ICursor c = new JavaCursor(preparedStatement.executeQuery()); + while (c.moveToNext()) { + func.apply(c); + } + c.close(); + preparedStatement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public Connection getConnection() { + return connection; + } +} diff --git a/src/main/java/net/bither/implbitherj/TxNotificationCenter.java b/src/main/java/net/bither/implbitherj/TxNotificationCenter.java index 46ca374..be59f64 100644 --- a/src/main/java/net/bither/implbitherj/TxNotificationCenter.java +++ b/src/main/java/net/bither/implbitherj/TxNotificationCenter.java @@ -67,7 +67,7 @@ public static void addTxListener(ITxListener txListener) { } public static void removeTxListener(ITxListener txListener) { - txListenerList.add(txListener); + txListenerList.remove(txListener); } private static void notifyCoins(String address, final long amount, diff --git a/src/main/java/net/bither/languages/MessageKey.java b/src/main/java/net/bither/languages/MessageKey.java index 3c1886a..089e442 100755 --- a/src/main/java/net/bither/languages/MessageKey.java +++ b/src/main/java/net/bither/languages/MessageKey.java @@ -805,7 +805,16 @@ public enum MessageKey { add_hd_account_seed_qr_phrase("add_hd_account_seed_qr_phrase"), import_hd_account_seed_qr_code("import_hd_account_seed_qr_code"), import_hd_account_seed_phrase("import_hd_account_seed_phrase"), - vanity_address_option("vanity_address_option") + vanity_address_option("vanity_address_option"), + address("address"), + add_desktop_hdm_cold_keychain("add_desktop_hdm_cold_keychain"), + add_desktop_hdm_hot_keychain("add_desktop_hdm_hot_keychain"), + desktop_hdm_first_account("desktop_hdm_first_account"), + desktop_hdm_second_account("desktop_hdm_second_account"), + import_desktop_hdm_first_account("import_desktop_hdm_first_account"), + import_desktop_hdm_second_account("import_desktop_hdm_second_account"), + desktop_enterprise_hdm("desktop_enterprise_hdm"), + select_camera("select_camera") // End of enum diff --git a/src/main/java/net/bither/qrcode/DesktopQRCodReceive.java b/src/main/java/net/bither/qrcode/DesktopQRCodReceive.java new file mode 100644 index 0000000..268f19b --- /dev/null +++ b/src/main/java/net/bither/qrcode/DesktopQRCodReceive.java @@ -0,0 +1,78 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.qrcode; + +import net.bither.bitherj.qrcode.QRCodeTransportPage; +import net.bither.bitherj.qrcode.QRCodeUtil; +import net.bither.bitherj.utils.Utils; + +import java.util.ArrayList; +import java.util.List; + +public class DesktopQRCodReceive { + private int sendCode; + private int sumPage; + private int currentPage; + + private List qrCodeTransportPageList = new ArrayList(); + + + public String getShowMsg() { + String[] headers = new String[]{Integer.toString(sendCode), + Integer.toString(sumPage), Integer.toString(currentPage)}; + String sendHeader = Utils.joinString(headers, QRCodeUtil.QR_CODE_SPLIT); + return sendHeader; + } + + public boolean receiveComplete() { + return currentPage == sumPage; + } + + public String getReceiveResult() { + if (currentPage == sumPage) { + return QRCodeTransportPage.qrCodeTransportToString(qrCodeTransportPageList); + } else { + return null; + } + } + + public void receiveMsg(String msg) { + if (QRCodeUtil.verifyBitherQRCode(msg)) { + String[] strings = QRCodeUtil.splitString(msg); + int sendCode = Integer.valueOf(strings[0]); + int sumPage = Integer.valueOf(strings[1]); + int currentPage = Integer.valueOf(strings[2]); + if (sendCode > DesktopQRCodSend.QRCodeSendCode) { + DesktopQRCodSend.QRCodeSendCode = sendCode; + } + if (sendCode == this.sendCode && sumPage == this.sumPage && currentPage == this.currentPage) { + return; + } + this.sendCode = sendCode; + this.sumPage = sumPage; + this.currentPage = currentPage; + String qrCodeTransport = msg.substring(strings[0].length() + 1); + qrCodeTransportPageList.add(QRCodeTransportPage.formatQrCodeTransport(qrCodeTransport)); + + } + + } + + +} diff --git a/src/main/java/net/bither/qrcode/DesktopQRCodSend.java b/src/main/java/net/bither/qrcode/DesktopQRCodSend.java new file mode 100644 index 0000000..e35efda --- /dev/null +++ b/src/main/java/net/bither/qrcode/DesktopQRCodSend.java @@ -0,0 +1,131 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.qrcode; + +import net.bither.bitherj.core.AbstractHD; +import net.bither.bitherj.core.DesktopHDMAddress; +import net.bither.bitherj.core.Tx; +import net.bither.bitherj.qrcode.QRCodeTxTransport; +import net.bither.bitherj.qrcode.QRCodeUtil; +import net.bither.bitherj.utils.Utils; +import net.bither.utils.LocaliserUtils; + +import java.util.List; + +public class DesktopQRCodSend { + + public static int QRCodeSendCode = 1; + private static byte[] lock = new byte[0]; + private java.util.List contents; + private int sendCode; + private int currentPage; + private String receiveMsg; + + + public DesktopQRCodSend(Tx tx, List desktopHDMAddresses, String changeAddress) { + synchronized (lock) { + QRCodeSendCode++; + this.sendCode = QRCodeSendCode; + String codeString = QRCodeTxTransport.getDeskpHDMPresignTxString(QRCodeTxTransport.TxTransportType.DesktopHDM, + tx, changeAddress, + LocaliserUtils.getString("address_cannot_be_parsed"), desktopHDMAddresses); + this.contents = QRCodeUtil.getQrCodeStringList(QRCodeUtil.encodeQrCodeString(codeString)); + this.currentPage = 0; + + } + + } + + public DesktopQRCodSend(String codeString) { + synchronized (lock) { + QRCodeSendCode++; + this.sendCode = QRCodeSendCode; + this.contents = QRCodeUtil.getQrCodeStringList(QRCodeUtil.encodeQrCodeString(codeString)); + this.currentPage = 0; + + } + + } + + public int getSendCode() { + return this.sendCode; + } + + public boolean sendFinish() { + return currentPage >= this.contents.size() - 1; + } + + public boolean canNextPage() { + String[] headers = new String[]{Integer.toString(sendCode), + Integer.toString(contents.size() - 1), Integer.toString(currentPage)}; + String sendHeader = Utils.joinString(headers, QRCodeUtil.QR_CODE_SPLIT); + return Utils.compareString(sendHeader, receiveMsg); + } + + + public void nextPage() { + currentPage++; + } + + public String getShowMessage() { + String msg = ""; + String[] headers = new String[]{Integer.toString(sendCode), + Integer.toString(contents.size() - 1), Integer.toString(currentPage)}; + String sendHeader = Utils.joinString(headers, QRCodeUtil.QR_CODE_SPLIT); + if (this.contents.size() == 1) { + msg = sendHeader + QRCodeUtil.QR_CODE_SPLIT + this.contents.get(0); + } else { + if (currentPage < this.contents.size()) { + msg = Integer.toString(sendCode) + QRCodeUtil.QR_CODE_SPLIT + this.contents.get(currentPage); + } + + } + return msg; + } + + public void setReceiveMsg(String msg) { + + String[] strings = QRCodeUtil.splitString(msg); + if (Utils.isInteger(strings[0])) { + int sendCode = Integer.valueOf(strings[0]); + if (sendCode > QRCodeSendCode) { + QRCodeSendCode = sendCode; + } + } + this.receiveMsg = msg; + } + + + public static int getSendCodeFromMsg(String msg) { + String[] strings = QRCodeUtil.splitString(msg); + int sendCode = Integer.valueOf(strings[0]); + return sendCode; + } + + + @Override + public boolean equals(Object obj) { + if (obj instanceof DesktopQRCodSend) { + DesktopQRCodSend other = (DesktopQRCodSend) obj; + return sendCode == other.sendCode; + + } + return false; + } +} diff --git a/src/main/java/net/bither/qrcode/SelectQRCodePanel.java b/src/main/java/net/bither/qrcode/SelectQRCodePanel.java index 29cd505..b33bc0e 100644 --- a/src/main/java/net/bither/qrcode/SelectQRCodePanel.java +++ b/src/main/java/net/bither/qrcode/SelectQRCodePanel.java @@ -50,7 +50,6 @@ public interface IFileChooser { public SelectQRCodePanel(IScanQRCode scanQRCode) { super(MessageKey.QR_CODE, AwesomeIcon.QRCODE); this.scanQRCode = scanQRCode; - } @Override diff --git a/src/main/java/net/bither/runnable/CommitTransactionThread.java b/src/main/java/net/bither/runnable/CommitTransactionThread.java index 07764cc..beedb4e 100644 --- a/src/main/java/net/bither/runnable/CommitTransactionThread.java +++ b/src/main/java/net/bither/runnable/CommitTransactionThread.java @@ -57,7 +57,9 @@ public void run() { boolean success = false; try { PeerManager.instance().publishTransaction(tx); - TransactionsUtil.removeSignTx(new UnSignTransaction(tx, wallet.getAddress())); + if (wallet != null) { + TransactionsUtil.removeSignTx(new UnSignTransaction(tx, wallet.getAddress())); + } success = true; } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/net/bither/runnable/CompleteTransactionRunnable.java b/src/main/java/net/bither/runnable/CompleteTransactionRunnable.java index 3d52f9b..24defea 100644 --- a/src/main/java/net/bither/runnable/CompleteTransactionRunnable.java +++ b/src/main/java/net/bither/runnable/CompleteTransactionRunnable.java @@ -146,7 +146,7 @@ public void run() { } - public String getMessageFromException(Exception e) { + public static String getMessageFromException(Exception e) { if (e != null && e instanceof TxBuilderException) { return e.getMessage(); } else if (e != null && e instanceof PasswordException) { diff --git a/src/main/java/net/bither/service/Server.java b/src/main/java/net/bither/service/Server.java new file mode 100644 index 0000000..90d5089 --- /dev/null +++ b/src/main/java/net/bither/service/Server.java @@ -0,0 +1,188 @@ +/* + * + * * Copyright 2014 http://Bither.net + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * 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. + * + */ + +package net.bither.service; + +import net.bither.Bither; +import net.bither.BitherSetting; +import net.bither.bitherj.BitherjSettings; +import net.bither.bitherj.core.AddressManager; +import net.bither.bitherj.core.DesktopHDMKeychain; +import net.bither.bitherj.core.PeerManager; +import net.bither.bitherj.utils.Utils; +import net.bither.preference.UserPreference; +import org.json.JSONArray; +import org.json.JSONObject; + +import javax.annotation.Nullable; +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class Server { + private static Thread instanceListenerThread; + private static boolean shutdownSocket = false; + + public static void main() throws IOException { + int port = 8326; + final ServerSocket server = new ServerSocket(port); + instanceListenerThread = new Thread(new Runnable() { + @Override + public void run() { + try { + while (!shutdownSocket) { + Socket socket = server.accept(); + new Thread(new Task(socket)).start(); + } + if (!server.isClosed()) { + server.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + instanceListenerThread.start(); + } + + static class Task implements Runnable { + + private Socket socket; + + public Task(Socket socket) { + this.socket = socket; + } + + public void run() { + try { + handleSocket(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void handleSocket() throws Exception { + BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); + Writer writer = new OutputStreamWriter(socket.getOutputStream()); + String command; + while ((command = br.readLine()) != null) { + String result; + if (command.equals("exit")) { + result = "bye"; + writer.write(result); + writer.write("\n"); + writer.flush(); + break; + } else { + result = this.execute(command); + writer.write(result); + writer.write("\n"); + writer.flush(); + } + } + writer.close(); + br.close(); + socket.close(); + } + + private String execute(String command) { + String[] sub = command.split(" "); + + if (Utils.compareString(sub[0], "hello")) { + return "hello"; + } else if (Utils.compareString(sub[0], "getbalance")) { + return this.getBalance(); + } else if (Utils.compareString(sub[0], "getaddress")) { + return this.getAddress(); + } else if (Utils.compareString(sub[0], "sendtx") && sub.length >= 3) { + if (sub.length == 4) { + return this.sendTx(sub[1], sub[2], Integer.valueOf(sub[3])); + } else { + return this.sendTx(sub[1], sub[2], null); + } + } else if (Utils.compareString(sub[0], "startpeer")) { + return this.startPeer(); + } else { + return Utils.format("not support command: %s", command); + } + } + + private String getBalance() { + return "0"; + } + + private String getAddress() { + if (AddressManager.getInstance().hasDesktopHDMKeychain() + && UserPreference.getInstance().getAppMode() == BitherjSettings.AppMode.HOT) { + String address = AddressManager.getInstance().getDesktopHDMKeychains().get(0).externalAddress(); + JSONObject result = new JSONObject(); + result.put("address", address); + return result.toString(); + } + JSONObject result = new JSONObject(); + result.put("result", false); + return result.toString(); + } + + private String startPeer() { + if (!PeerManager.instance().isRunning()) { + PeerManager.instance().start(); + } + JSONObject result = new JSONObject(); + result.put("result", true); + return result.toString(); + } + + private String sendTx(String sendRequest, String password, @Nullable Integer feeBaseMode) { + if (AddressManager.getInstance().hasDesktopHDMKeychain() + && UserPreference.getInstance().getAppMode() == BitherjSettings.AppMode.HOT) { + DesktopHDMKeychain keychain = AddressManager.getInstance().getDesktopHDMKeychains().get(0); + JSONObject jsonObject = new JSONObject(sendRequest); + JSONArray addressesJSonArray = jsonObject.getJSONArray("addresses"); + JSONArray amountsJSonArray = jsonObject.getJSONArray("amounts"); + + HashMap sr = new HashMap(); + for (int i = 0; i < addressesJSonArray.length(); i++) { + String tmp = amountsJSonArray.getString(i); + sr.put(addressesJSonArray.getString(i), amountsJSonArray.getLong(i)); + } + try { + keychain.getSendRequestList().put(sr); + } catch (InterruptedException e) { + e.printStackTrace(); + JSONObject result = new JSONObject(); + result.put("error", e.getMessage()); + return result.toString(); + } + JSONObject result = new JSONObject(); + result.put("result", true); + return result.toString(); + } + JSONObject result = new JSONObject(); + result.put("result", false); + return result.toString(); + } + } + + public static void shutdownSocket() { + shutdownSocket = true; + } +} diff --git a/src/main/java/net/bither/utils/FileUtil.java b/src/main/java/net/bither/utils/FileUtil.java index 1ec46cd..1fce212 100644 --- a/src/main/java/net/bither/utils/FileUtil.java +++ b/src/main/java/net/bither/utils/FileUtil.java @@ -62,8 +62,11 @@ public class FileUtil { private static final String BITHER_BACKUP_SDCARD_DIR = "BitherBackup"; private static final String BITHER_BACKUP_ROM_DIR = "backup"; + private static final String BITHER_BACKUP_HOT_FILE_NAME = "keys"; + private static final String SEND_BITCOIN_FOLDER = "send"; + public static File getExchangeRateFile() { File file = getDir(""); return new File(file, EXCHANGERATE); @@ -155,6 +158,15 @@ public static File getBackupDir() { return backupDir; } + public static File getSendBitcoinDir() { + File dir = getDir(SEND_BITCOIN_FOLDER); + if (!dir.exists()) { + dir.mkdirs(); + } + return dir; + + } + public static File getBackupFile() { File file = new File(getBackupDir(), DateUtils.getNameForFile(System.currentTimeMillis()) diff --git a/src/main/java/net/bither/utils/KeyUtil.java b/src/main/java/net/bither/utils/KeyUtil.java index 2e1bbc6..8429f24 100644 --- a/src/main/java/net/bither/utils/KeyUtil.java +++ b/src/main/java/net/bither/utils/KeyUtil.java @@ -43,7 +43,7 @@ public static List
addPrivateKeyByRandomWithPassphras(IUEntropy iuEntro ECKey ecKey = ECKey.generateECKey(xRandom); ecKey = PrivateKeyUtil.encrypt(ecKey, password); Address address = new Address(ecKey.toAddress(), - ecKey.getPubKey(), PrivateKeyUtil.getEncryptedString(ecKey), ecKey.isFromXRandom()); + ecKey.getPubKey(), PrivateKeyUtil.getEncryptedString(ecKey), true, ecKey.isFromXRandom()); ecKey.clearPrivateKey(); addressList.add(address); AddressManager.getInstance().addAddress(address); @@ -98,8 +98,17 @@ public static void setHDKeyChain(HDMKeychain keyChain) { } + public static void setDesktopHMDKeychains(List keychains) { + AddressManager.getInstance().setDesktopHDMKeychains(keychains); + if (UserPreference.getInstance().getAppMode() == BitherjSettings.AppMode.COLD) { + BackupUtil.backupColdKey(false); + } else { + BackupUtil.backupHotKey(); + } + } + public static void setHDAccount(HDAccount hdAccount) { - AddressManager.getInstance().setHdAccount(hdAccount); + AddressManager.getInstance().setHdAccountHot(hdAccount); if (UserPreference.getInstance().getAppMode() == BitherjSettings.AppMode.COLD) { BackupUtil.backupColdKey(false); } else { diff --git a/src/main/java/net/bither/viewsystem/MainFrameUI.java b/src/main/java/net/bither/viewsystem/MainFrameUI.java index f63f3cb..1127cb5 100644 --- a/src/main/java/net/bither/viewsystem/MainFrameUI.java +++ b/src/main/java/net/bither/viewsystem/MainFrameUI.java @@ -342,8 +342,8 @@ public void updateHeader() { for (Address address : AddressManager.getInstance().getAllAddresses()) { finalEstimatedBalance = finalEstimatedBalance + address.getBalance(); } - if (AddressManager.getInstance().getHdAccount() != null) { - finalEstimatedBalance = finalEstimatedBalance + AddressManager.getInstance().getHdAccount().getBalance(); + if (AddressManager.getInstance().getHDAccountHot() != null) { + finalEstimatedBalance = finalEstimatedBalance + AddressManager.getInstance().getHDAccountHot().getBalance(); } final long total = finalEstimatedBalance; diff --git a/src/main/java/net/bither/viewsystem/action/ExitAction.java b/src/main/java/net/bither/viewsystem/action/ExitAction.java index 91bca68..d108f57 100755 --- a/src/main/java/net/bither/viewsystem/action/ExitAction.java +++ b/src/main/java/net/bither/viewsystem/action/ExitAction.java @@ -19,6 +19,7 @@ import net.bither.ApplicationInstanceManager; import net.bither.Bither; import net.bither.bitherj.core.PeerManager; +import net.bither.service.Server; import net.bither.utils.LocaliserUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,6 +63,7 @@ public void run() { } PeerManager.instance().stop(); ApplicationInstanceManager.shutdownSocket(); + Server.shutdownSocket(); // Get rid of main display. if (Bither.getMainFrame() != null) { diff --git a/src/main/java/net/bither/viewsystem/base/Buttons.java b/src/main/java/net/bither/viewsystem/base/Buttons.java index feefaea..4a848f5 100755 --- a/src/main/java/net/bither/viewsystem/base/Buttons.java +++ b/src/main/java/net/bither/viewsystem/base/Buttons.java @@ -1000,6 +1000,21 @@ public static JButton newLargeReloadTxWizardButton(Action action) { return button; } + public static JButton newExcahngeWizardButton(Action action) { + + JButton button = newLargeButton(action, MessageKey.EXCHANGE_SETTINGS_TITLE); + + AwesomeDecorator.applyIcon( + AwesomeIcon.DOLLAR, + button, + true, + JLabel.BOTTOM, + BitherUI.LARGE_ICON_SIZE + ); + + return button; + } + public static JButton newLargeRecoveryButton(Action action) { JButton button = newLargeButton(action, MessageKey.address_group_hdm_recovery); AwesomeDecorator.applyIcon( diff --git a/src/main/java/net/bither/viewsystem/dialogs/AbstractDesktopHDMMsgDialog.form b/src/main/java/net/bither/viewsystem/dialogs/AbstractDesktopHDMMsgDialog.form new file mode 100644 index 0000000..38148fc --- /dev/null +++ b/src/main/java/net/bither/viewsystem/dialogs/AbstractDesktopHDMMsgDialog.form @@ -0,0 +1,63 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/net/bither/viewsystem/dialogs/AbstractDesktopHDMMsgDialog.java b/src/main/java/net/bither/viewsystem/dialogs/AbstractDesktopHDMMsgDialog.java new file mode 100644 index 0000000..5849a5b --- /dev/null +++ b/src/main/java/net/bither/viewsystem/dialogs/AbstractDesktopHDMMsgDialog.java @@ -0,0 +1,268 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.viewsystem.dialogs; + +import com.github.sarxos.webcam.Webcam; +import com.github.sarxos.webcam.WebcamPanel; +import com.github.sarxos.webcam.WebcamResolution; +import com.google.zxing.*; +import com.google.zxing.client.j2se.BufferedImageLuminanceSource; +import com.google.zxing.common.HybridBinarizer; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.uiDesigner.core.Spacer; +import net.bither.Bither; +import net.bither.BitherUI; +import net.bither.qrcode.DesktopQRCodReceive; +import net.bither.qrcode.DesktopQRCodSend; +import net.bither.qrcode.QRCodeGenerator; +import net.bither.utils.LocaliserUtils; +import net.bither.viewsystem.base.Labels; +import net.bither.viewsystem.base.Panels; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import java.awt.*; +import java.awt.Dimension; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import java.awt.image.VolatileImage; +import java.util.ResourceBundle; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + +public abstract class AbstractDesktopHDMMsgDialog extends JDialog implements Runnable, ThreadFactory { + private JPanel contentPane; + private JButton buttonCancel; + private JPanel mainPanel; + protected JLabel labMsg; + private Executor executor = Executors.newSingleThreadExecutor(this); + + private JLabel imageLabel; + + private Webcam webcam = null; + private WebcamPanel panel = null; + + protected boolean isRunning = true; + + protected DesktopQRCodSend desktopQRCodSend; + protected DesktopQRCodReceive desktopQRCodReceive; + + + protected boolean isSendMode; + + public AbstractDesktopHDMMsgDialog(Webcam webcam) { + setContentPane(contentPane); + this.webcam = webcam; + setModal(true); + getRootPane().setDefaultButton(buttonCancel); + + + buttonCancel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }); + + + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + contentPane.registerKeyboardAction(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + initialiseContent(); + + Dimension dimension = Bither.getMainFrame().getSize(); + setMinimumSize(dimension); + setPreferredSize(dimension); + setMaximumSize(dimension); + setSize(dimension); + // initDialog(); + executor.execute(this); + inited(); + } + + public void onCancel() { + if (webcam.isOpen()) { + webcam.close(); + } + isRunning = false; + + dispose(); + } + + public void initialiseContent() { + mainPanel.setLayout(new MigLayout( + Panels.migXYLayout(), + "[][]", // Column constraints + "[][]" // Row constraints + )); + imageLabel = Labels.newValueLabel(""); + mainPanel.add(imageLabel, "align center,cell 0 0,grow"); + + Dimension size = WebcamResolution.QVGA.getSize(); + java.util.List webcams = Webcam.getWebcams(); + if (webcams.size() > 0) { + webcam.setViewSize(size); + panel = new WebcamPanel(webcam); + panel.setPreferredSize(size); + mainPanel.add(panel, "align center,cell 1 0,grow"); + + } else { + dispose(); + new MessageDialog(LocaliserUtils.getString("camer_is_not_available")).showMsg(); + } + } + + + protected void showQRCode(String qrCodeString) { + int scaleWidth = BitherUI.UI_MIN_HEIGHT; + int scaleHeight = BitherUI.UI_MIN_HEIGHT; + Image image = QRCodeGenerator.generateQRcode(qrCodeString, null, null, 1); + if (image != null) { + int scaleFactor = (int) (Math.floor(Math.min(scaleHeight / image.getHeight(null), + scaleWidth / image.getWidth(null)))); + BufferedImage qrCodeImage = QRCodeGenerator.generateQRcode(qrCodeString, null, null, scaleFactor); + imageLabel.setIcon(new ImageIcon(qrCodeImage)); + } + + } + + @Override + public void run() { + do { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Result result = null; + BufferedImage image = null; + if (webcam.isOpen()) { + if ((image = webcam.getImage()) == null) { + continue; + } + LuminanceSource source = new BufferedImageLuminanceSource(image); + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + + try { + result = new MultiFormatReader().decode(bitmap); + + } catch (NotFoundException e) { + + } + } + if (result != null && result.getText() != null) { + handleScanResult(result.getText()); + + } + + + } while (isRunning); + } + + protected abstract void handleScanResult(final String result); + + protected abstract void inited(); + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, "example-runner"); + t.setDaemon(true); + return t; + } + + { +// GUI initializer generated by IntelliJ IDEA GUI Designer +// >>> IMPORTANT!! <<< +// DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + contentPane = new JPanel(); + contentPane.setLayout(new GridLayoutManager(2, 1, new Insets(10, 10, 10, 10), -1, -1)); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new GridLayoutManager(1, 3, new Insets(0, 0, 0, 0), -1, -1)); + contentPane.add(panel1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, 1, null, null, null, 0, false)); + final Spacer spacer1 = new Spacer(); + panel1.add(spacer1, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + panel1.add(panel2, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + buttonCancel = new JButton(); + this.$$$loadButtonText$$$(buttonCancel, ResourceBundle.getBundle("viewer").getString("cancel")); + panel2.add(buttonCancel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + labMsg = new JLabel(); + labMsg.setText(""); + panel1.add(labMsg, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + mainPanel = new JPanel(); + mainPanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); + contentPane.add(mainPanel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + } + + /** + * @noinspection ALL + */ + private void $$$loadButtonText$$$(AbstractButton component, String text) { + StringBuffer result = new StringBuffer(); + boolean haveMnemonic = false; + char mnemonic = '\0'; + int mnemonicIndex = -1; + for (int i = 0; i < text.length(); i++) { + if (text.charAt(i) == '&') { + i++; + if (i == text.length()) break; + if (!haveMnemonic && text.charAt(i) != '&') { + haveMnemonic = true; + mnemonic = text.charAt(i); + mnemonicIndex = result.length(); + } + } + result.append(text.charAt(i)); + } + component.setText(result.toString()); + if (haveMnemonic) { + component.setMnemonic(mnemonic); + component.setDisplayedMnemonicIndex(mnemonicIndex); + } + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() { + return contentPane; + } +} diff --git a/src/main/java/net/bither/viewsystem/froms/AdvancePanel.java b/src/main/java/net/bither/viewsystem/froms/AdvancePanel.java index 6ef038f..f844218 100644 --- a/src/main/java/net/bither/viewsystem/froms/AdvancePanel.java +++ b/src/main/java/net/bither/viewsystem/froms/AdvancePanel.java @@ -27,7 +27,8 @@ import net.bither.bitherj.crypto.PasswordSeed; import net.bither.bitherj.crypto.SecureCharSequence; import net.bither.bitherj.utils.TransactionsUtil; -import net.bither.db.HDAccountProvider; +import net.bither.db.DesktopTxProvider; +import net.bither.db.HDAccountAddressProvider; import net.bither.db.TxProvider; import net.bither.fonts.AwesomeIcon; import net.bither.languages.MessageKey; @@ -53,12 +54,15 @@ public class AdvancePanel extends WizardPanel { private JRadioButton rbNormal; - private JRadioButton rbLow; + private JRadioButton rbHigh; + private JRadioButton rbHigher; + private JRadioButton rbTimes10; private JButton btnSwitchCold; private JButton btnReloadTx; private JButton btnRecovery; private JButton btnRestHDMPassword; + private JButton btnExchange; private DialogProgress dp; private HDMKeychainRecoveryUtil hdmRecoveryUtil; private HDMResetServerPasswordUtil hdmResetServerPasswordUtil; @@ -71,26 +75,46 @@ public AdvancePanel() { @Override public void initialiseContent(JPanel panel) { + System.out.println(UserPreference.getInstance().getTransactionFeeMode().getMinFeeSatoshi() + "............................................."); panel.setLayout(new MigLayout( Panels.migXYLayout(), "[][][]", // Column constraints "[][][][][][]" // Row constraints )); - rbLow = getRbLow(); + rbNormal = getRbNormal(); + rbHigh = getRbHigh(); + rbHigher = getRbHigher(); + rbTimes10 = getRbTimes10(); + ButtonGroup groupFee = new ButtonGroup(); - groupFee.add(rbLow); + groupFee.add(rbHigh); + groupFee.add(rbHigher); + groupFee.add(rbTimes10); groupFee.add(rbNormal); - if (UserPreference.getInstance().getTransactionFeeMode() == BitherjSettings.TransactionFeeMode.Normal) { - rbNormal.setSelected(true); - } else { - rbLow.setSelected(true); + + switch (UserPreference.getInstance().getTransactionFeeMode()){ + case Normal: + rbNormal.setSelected(true); + break; + case High: + rbHigh.setSelected(true); + break; + case Higher: + rbHigher.setSelected(true); + break; + case Times10: + rbTimes10.setSelected(true); + break; } + JLabel label = Labels.newValueLabel(LocaliserUtils.getString("setting_name_transaction_fee")); - panel.add(label, "push,align left"); - panel.add(rbNormal, "push,align left"); - panel.add(rbLow, "push,align left,wrap"); + panel.add(label, "push,gaptop 12,span 1 4,align left top"); + panel.add(rbNormal, "push,wrap"); + panel.add(rbHigh, "push,wrap"); + panel.add(rbHigher, "push,wrap"); + panel.add(rbTimes10, "push,wrap"); JCheckBox cbCheckPassword = RadioButtons.newCheckPassword(); panel.add(cbCheckPassword, "push,align left,wrap"); // panel.add(rbCheckPWDOn, "push,align left"); @@ -116,7 +140,21 @@ public void actionPerformed(ActionEvent e) { reloadTx(); } }); + + panel.add(btnReloadTx, "push,align left"); + if (UserPreference.getInstance().getAppMode() == BitherjSettings.AppMode.HOT) { + btnExchange = Buttons.newExcahngeWizardButton(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + closePanel(); + ExchangePreferencePanel exchangePreferencePanel = new ExchangePreferencePanel(); + exchangePreferencePanel.showPanel(); + + } + }); + panel.add(btnExchange, "push,align left"); + } if (hdmRecoveryUtil.canRecover()) { btnRecovery = Buttons.newLargeRecoveryButton(new AbstractAction() { @Override @@ -238,7 +276,7 @@ public void run() { } }); - jRadioButton.setText(LocaliserUtils.getString("setting_name_transaction_fee_low")); + jRadioButton.setText(LocaliserUtils.getString("setting_name_transaction_fee_high")); return jRadioButton; } @@ -258,14 +296,42 @@ public void actionPerformed(ActionEvent actionEvent) { return jRadioButton; } - private JRadioButton getRbLow() { + private JRadioButton getRbHigh() { + JRadioButton jRadioButton = new JRadioButton(); + + jRadioButton.setText(LocaliserUtils.getString("setting_name_transaction_fee_high")); + jRadioButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + UserPreference.getInstance().setTransactionFeeMode(BitherjSettings.TransactionFeeMode.High); + } + }); + return jRadioButton; + + } + + private JRadioButton getRbHigher() { + JRadioButton jRadioButton = new JRadioButton(); + + jRadioButton.setText(LocaliserUtils.getString("setting_name_transaction_fee_higher")); + jRadioButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + UserPreference.getInstance().setTransactionFeeMode(BitherjSettings.TransactionFeeMode.Higher); + } + }); + return jRadioButton; + + } + + private JRadioButton getRbTimes10() { JRadioButton jRadioButton = new JRadioButton(); - jRadioButton.setText(LocaliserUtils.getString("setting_name_transaction_fee_low")); + jRadioButton.setText(LocaliserUtils.getString("setting_name_transaction_fee_times10")); jRadioButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { - UserPreference.getInstance().setTransactionFeeMode(BitherjSettings.TransactionFeeMode.Low); + UserPreference.getInstance().setTransactionFeeMode(BitherjSettings.TransactionFeeMode.Times10); } }); return jRadioButton; @@ -340,7 +406,8 @@ public void run() { address.updateSyncComplete(); } - HDAccountProvider.getInstance().setSyncdNotComplete(); + HDAccountAddressProvider.getInstance().setSyncedNotComplete(); + DesktopTxProvider.getInstance().setSyncdNotComplete(); TxProvider.getInstance().clearAllTx(); for (Address address : AddressManager.getInstance().getAllAddresses()) { address.notificatTx(null, Tx.TxNotificationType.txFromApi); diff --git a/src/main/java/net/bither/viewsystem/froms/CheckPrivateKeyPanel.java b/src/main/java/net/bither/viewsystem/froms/CheckPrivateKeyPanel.java index 1d10591..9903b43 100644 --- a/src/main/java/net/bither/viewsystem/froms/CheckPrivateKeyPanel.java +++ b/src/main/java/net/bither/viewsystem/froms/CheckPrivateKeyPanel.java @@ -81,7 +81,7 @@ public void initialiseContent(JPanel panel) { )); addressCheckList = new ArrayList(); - HDAccount hdAccount = AddressManager.getInstance().getHdAccount(); + HDAccount hdAccount = AddressManager.getInstance().getHDAccountHot(); if (hdAccount != null) { addressCheckList.add(new AddressCheck(AddressCheck.CheckType.HDAccount, LocaliserUtils.getString("add_hd_account_tab_hd"), AddressCheck.CheckStatus.Prepare)); @@ -117,7 +117,7 @@ public void initialiseContent(JPanel panel) { @Override public void actionPerformed(ActionEvent e) { if (AddressManager.getInstance().getPrivKeyAddresses().size() > 0 || AddressManager.getInstance().getHdmKeychain() != null - || AddressManager.getInstance().getHdAccount() != null) { + || AddressManager.getInstance().getHDAccountHot() != null) { PasswordPanel dialogPassword = new PasswordPanel((CheckPrivateKeyPanel.this)); dialogPassword.showPanel(); @@ -177,7 +177,7 @@ public void beginCheck(SecureCharSequence password) { point = new CheckPoint(addressCheck); checkPoints.add(point); checks.add(CheckUtil.initCheckForHDAccount(AddressManager.getInstance() - .getHdAccount(), new SecureCharSequence(password)).setCheckListener(point)); + .getHDAccountHot(), new SecureCharSequence(password)).setCheckListener(point)); break; } diff --git a/src/main/java/net/bither/viewsystem/froms/ExportPrivateKeyPanel.java b/src/main/java/net/bither/viewsystem/froms/ExportPrivateKeyPanel.java index 21cae07..e173d09 100644 --- a/src/main/java/net/bither/viewsystem/froms/ExportPrivateKeyPanel.java +++ b/src/main/java/net/bither/viewsystem/froms/ExportPrivateKeyPanel.java @@ -61,7 +61,7 @@ public class ExportPrivateKeyPanel extends WizardPanel implements IDialogPasswor public ExportPrivateKeyPanel() { super(MessageKey.EXPORT, AwesomeIcon.FA_SIGN_OUT); keychain = AddressManager.getInstance().getHdmKeychain(); - hdAccount = AddressManager.getInstance().getHdAccount(); + hdAccount = AddressManager.getInstance().getHDAccountHot(); } diff --git a/src/main/java/net/bither/viewsystem/froms/HDAccountAddPanel.java b/src/main/java/net/bither/viewsystem/froms/HDAccountAddPanel.java index 27d2b7a..84569fd 100644 --- a/src/main/java/net/bither/viewsystem/froms/HDAccountAddPanel.java +++ b/src/main/java/net/bither/viewsystem/froms/HDAccountAddPanel.java @@ -22,6 +22,7 @@ import net.bither.bitherj.core.AddressManager; import net.bither.bitherj.core.HDAccount; import net.bither.bitherj.crypto.SecureCharSequence; +import net.bither.bitherj.crypto.mnemonic.MnemonicException; import net.bither.bitherj.delegate.IPasswordGetterDelegate; import net.bither.fonts.AwesomeIcon; import net.bither.languages.MessageKey; @@ -52,7 +53,7 @@ public class HDAccountAddPanel extends WizardPanel implements IPasswordGetterDel public HDAccountAddPanel() { super(MessageKey.add_hd_account_tab_hd, AwesomeIcon.HEADER); - hdAccount = AddressManager.getInstance().getHdAccount(); + hdAccount = AddressManager.getInstance().getHDAccountHot(); passwordGetter = new PasswordPanel.PasswordGetter(HDAccountAddPanel.this); setOkAction(new AbstractAction() { @@ -77,12 +78,17 @@ public void run() { accountUEntropyDialog.setVisible(true); } else { - HDAccount account = new HDAccount(new SecureRandom(), password, new HDAccount.HDAccountGenerationDelegate() { - @Override - public void onHDAccountGenerationProgress(double progress) { - - } - }); + HDAccount account = null; + try { + account = new HDAccount(new SecureRandom(), password, new HDAccount.HDAccountGenerationDelegate() { + @Override + public void onHDAccountGenerationProgress(double progress) { + + } + }); + } catch (MnemonicException.MnemonicLengthException e1) { + e1.printStackTrace(); + } KeyUtil.setHDAccount(account); password.wipe(); Bither.refreshFrame(); diff --git a/src/main/java/net/bither/viewsystem/froms/ImportPrivateKeyPanel.java b/src/main/java/net/bither/viewsystem/froms/ImportPrivateKeyPanel.java index 29c3bfc..28822bf 100644 --- a/src/main/java/net/bither/viewsystem/froms/ImportPrivateKeyPanel.java +++ b/src/main/java/net/bither/viewsystem/froms/ImportPrivateKeyPanel.java @@ -193,7 +193,7 @@ public void handleResult(String result, IReadQRCode readQRCode) { } } } else { - if (AddressManager.getInstance().getHdAccount() == null) { + if (AddressManager.getInstance().getHDAccountHot() == null) { panel.add(btnHDAccountSeed, "align center,cell 2 5,grow,wrap"); panel.add(btnHDAccountPhras, "align center,cell 2 6,grow,wrap"); } diff --git a/src/main/java/net/bither/viewsystem/froms/MenuBar.java b/src/main/java/net/bither/viewsystem/froms/MenuBar.java index 5879200..57abef4 100644 --- a/src/main/java/net/bither/viewsystem/froms/MenuBar.java +++ b/src/main/java/net/bither/viewsystem/froms/MenuBar.java @@ -331,8 +331,8 @@ public void run() { for (Address address : AddressManager.getInstance().getAllAddresses()) { finalEstimatedBalance = finalEstimatedBalance + address.getBalance(); } - if (AddressManager.getInstance().getHdAccount() != null) { - finalEstimatedBalance = finalEstimatedBalance + AddressManager.getInstance().getHdAccount().getBalance(); + if (AddressManager.getInstance().getHDAccountHot() != null) { + finalEstimatedBalance = finalEstimatedBalance + AddressManager.getInstance().getHDAccountHot().getBalance(); } final long total = finalEstimatedBalance; final String exchange = MarketUtil.getMarketName(UserPreference.getInstance().getDefaultMarket()); diff --git a/src/main/java/net/bither/viewsystem/froms/MorePanel.java b/src/main/java/net/bither/viewsystem/froms/MorePanel.java index 4a4a77a..571f1d6 100644 --- a/src/main/java/net/bither/viewsystem/froms/MorePanel.java +++ b/src/main/java/net/bither/viewsystem/froms/MorePanel.java @@ -19,7 +19,6 @@ package net.bither.viewsystem.froms; import net.bither.Bither; -import net.bither.BitherSetting; import net.bither.bitherj.BitherjSettings; import net.bither.bitherj.core.Address; import net.bither.bitherj.core.AddressManager; @@ -32,28 +31,41 @@ import net.bither.viewsystem.base.Panels; import net.bither.viewsystem.base.RadioButtons; import net.bither.viewsystem.dialogs.MessageDialog; +import net.bither.viewsystem.froms.desktop.hdm.DesktopHDMColdPanel; +import net.bither.viewsystem.froms.desktop.hdm.DesktopHDMHotPanel; import net.miginfocom.swing.MigLayout; import javax.swing.*; +import javax.swing.event.MouseInputAdapter; import java.awt.event.ActionEvent; +import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; public class MorePanel extends WizardPanel { + private static final int MouseClickedCount = 7; + private static final long MouseClickedTime = 5 * 1000; + private JButton btnAdvance; private JButton btnVanitygen; private JButton btnPeer; private JButton btnBlcok; - private JButton btnExchange; + private JButton btnVerfyMessage; private JButton btnSignMessage; private JButton btnDonate; private JButton btnChangePassword; + private JButton btnEnterpriseHDM; + + private long beginClickTime = System.currentTimeMillis(); + private int clickCount = 0; + public MorePanel() { super(MessageKey.MORE, AwesomeIcon.ELLIPSIS_H); + } @Override @@ -61,8 +73,23 @@ public void initialiseContent(JPanel panel) { panel.setLayout(new MigLayout( Panels.migXYLayout(), "[][][][][][][]", // Column constraints - "[][][][][][]" // Row constraints + "[][][][][]" // Row constraints )); + panel.addMouseListener(new MouseInputAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + if (System.currentTimeMillis() - beginClickTime < MouseClickedTime) { + clickCount++; + } else { + clickCount = 0; + } + beginClickTime = System.currentTimeMillis(); + if (clickCount == 7) { + btnEnterpriseHDM.setVisible(true); + } + } + }); btnAdvance = Buttons.newNormalButton(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { @@ -99,15 +126,7 @@ public void actionPerformed(ActionEvent e) { } }, MessageKey.BLOCKS, AwesomeIcon.FA_SHARE_ALT); - btnExchange = Buttons.newNormalButton(new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - closePanel(); - ExchangePreferencePanel exchangePreferencePanel = new ExchangePreferencePanel(); - exchangePreferencePanel.showPanel(); - } - }, MessageKey.EXCHANGE_SETTINGS_TITLE, AwesomeIcon.DOLLAR); btnVerfyMessage = Buttons.newNormalButton(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { @@ -149,16 +168,30 @@ public void actionPerformed(ActionEvent e) { } }, MessageKey.SHOW_CHANGE_PASSWORD_WIZARD, AwesomeIcon.LOCK); + btnEnterpriseHDM = Buttons.newNormalButton(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + closePanel(); + if (UserPreference.getInstance().getAppMode() == BitherjSettings.AppMode.HOT) { + DesktopHDMHotPanel desktopHDMHotPanel = new DesktopHDMHotPanel(); + desktopHDMHotPanel.showPanel(); + } else { + DesktopHDMColdPanel enterpriseColdPanel = new DesktopHDMColdPanel(); + enterpriseColdPanel.showPanel(); + } + } + }, MessageKey.desktop_enterprise_hdm, AwesomeIcon.HDD_O); + if (UserPreference.getInstance().getAppMode() == BitherjSettings.AppMode.HOT) { panel.add(btnChangePassword, "align center,cell 3 0 ,grow ,shrink,wrap"); panel.add(btnVanitygen, "align center,cell 3 1 ,grow ,shrink,wrap"); panel.add(btnAdvance, "align center,cell 3 2 ,shrink,grow,wrap"); - panel.add(btnExchange, "align center,cell 3 3,shrink,grow,wrap"); - panel.add(btnSignMessage, "align center,cell 3 4,shrink,grow,wrap"); - panel.add(btnVerfyMessage, "align center,cell 3 5,shrink,grow,wrap"); - panel.add(btnPeer, "align center,cell 3 6,shrink,grow,wrap"); - panel.add(btnBlcok, "align center,cell 3 7,shrink,grow,wrap"); +// panel.add(btnExchange, "align center,cell 3 3,shrink,grow,wrap"); + panel.add(btnSignMessage, "align center,cell 3 3,shrink,grow,wrap"); + panel.add(btnVerfyMessage, "align center,cell 3 4,shrink,grow,wrap"); + panel.add(btnPeer, "align center,cell 3 5,shrink,grow,wrap"); + panel.add(btnBlcok, " align center,cell 3 6,shrink,grow,wrap"); btnDonate = Buttons.newNormalButton(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { @@ -168,9 +201,9 @@ public void actionPerformed(ActionEvent e) { availableList.add(address); } } - if (AddressManager.getInstance().getHdAccount() != null - && AddressManager.getInstance().getHdAccount().getBalance() > 0) { - availableList.add(AddressManager.getInstance().getHdAccount()); + if (AddressManager.getInstance().getHDAccountHot() != null + && AddressManager.getInstance().getHDAccountHot().getBalance() > 0) { + availableList.add(AddressManager.getInstance().getHDAccountHot()); } if (availableList.size() == 0) { @@ -219,15 +252,17 @@ public void selectAddress(Address address) { } }, MessageKey.donate_button, AwesomeIcon.BITCOIN); - panel.add(btnDonate, "align center,cell 3 8,grow,shrink,wrap"); + panel.add(btnDonate, "align center,cell 3 7,grow,shrink,wrap"); + panel.add(btnEnterpriseHDM, "align center,cell 3 8,grow,shrink,wrap"); } else { panel.add(btnChangePassword, "align center,cell 3 0 ,shrink"); panel.add(btnVanitygen, "align center,cell 3 1 ,shrink"); JCheckBox cbCheckPassword = RadioButtons.newCheckPassword(); panel.add(cbCheckPassword, "align center,cell 3 2 ,shrink"); - + panel.add(btnEnterpriseHDM, "align center,cell 3 4,shrink,wrap"); } - + btnEnterpriseHDM.setVisible(false); } + } diff --git a/src/main/java/net/bither/viewsystem/froms/SelectWebcamPanel.java b/src/main/java/net/bither/viewsystem/froms/SelectWebcamPanel.java new file mode 100644 index 0000000..c35acee --- /dev/null +++ b/src/main/java/net/bither/viewsystem/froms/SelectWebcamPanel.java @@ -0,0 +1,160 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.viewsystem.froms; + +import com.github.sarxos.webcam.Webcam; +import net.bither.BitherSetting; +import net.bither.fonts.AwesomeIcon; +import net.bither.languages.MessageKey; +import net.bither.utils.LocaliserUtils; +import net.bither.viewsystem.base.FontSizer; +import net.bither.viewsystem.base.Panels; +import net.bither.viewsystem.base.renderer.SelectAddressImage; +import net.bither.viewsystem.components.ScrollBarUIDecorator; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.table.AbstractTableModel; +import java.awt.*; + +public class SelectWebcamPanel extends WizardPanel implements ListSelectionListener { + + public interface ISelectWencamListener { + public void onSelect(Webcam webcam); + } + + private JTable tbDevices; + + private Webcam selectedWebcam; + + java.util.List webcams = Webcam.getWebcams(); + + private JScrollPane sp; + private ISelectWencamListener selectWencamListener; + + public SelectWebcamPanel(ISelectWencamListener selectWencamListener) { + super(MessageKey.select_camera, AwesomeIcon.FA_LIST); + this.selectWencamListener = selectWencamListener; + } + + @Override + public void initialiseContent(JPanel panel) { + panel.setLayout(new MigLayout( + Panels.migXYLayout(), + "10[]10", // Column constraints + "10[]10" // Row constraints + )); + + tbDevices = new JTable(selectDeviceTableModel); + tbDevices.getColumnModel().getColumn(0).setResizable(true); + tbDevices.getColumnModel().getColumn(1).setResizable(true); + + tbDevices.getColumnModel().getColumn(1).setMinWidth(1); + tbDevices.getColumnModel().getColumn(1).setPreferredWidth(Integer.MAX_VALUE); + + tbDevices.getColumnModel().getColumn(0).setMinWidth(20); + tbDevices.getColumnModel().getColumn(0).setPreferredWidth(20); + tbDevices.getColumnModel().getColumn(0).setCellRenderer(new SelectAddressImage()); + tbDevices.setOpaque(true); + tbDevices.setAutoCreateColumnsFromModel(true); + tbDevices.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + tbDevices.setAutoscrolls(true); + tbDevices.setBorder(BorderFactory.createEmptyBorder()); + tbDevices.setComponentOrientation(ComponentOrientation.getOrientation(LocaliserUtils + .getLocale())); + tbDevices.setRowHeight(Math.max(BitherSetting.MINIMUM_ICON_HEIGHT, panel.getFontMetrics + (FontSizer.INSTANCE.getAdjustedDefaultFont()).getHeight()) + BitherSetting + .HEIGHT_DELTA * 2); + sp = new JScrollPane(); + sp.setViewportView(tbDevices); + ScrollBarUIDecorator.apply(sp, false); + tbDevices.getSelectionModel().addListSelectionListener(this); + panel.add(sp, "push, grow"); + } + + @Override + public void showPanel() { + super.showPanel(); + if (webcams.size() == 1) { + closePanel(); + if (selectWencamListener != null) { + selectWencamListener.onSelect(webcams.get(0)); + + } + } + + + } + + private AbstractTableModel selectDeviceTableModel = new AbstractTableModel() { + @Override + public int getRowCount() { + return webcams == null ? 0 : webcams.size(); + } + + @Override + public int getColumnCount() { + return 2; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + switch (columnIndex) { + case 1: + return webcams.get(rowIndex).getName(); + case 0: + return webcams.get(rowIndex).equals(selectedWebcam); + } + return null; + } + + @Override + public String getColumnName(int column) { + return ""; + } + }; + + @Override + public void valueChanged(ListSelectionEvent e) { + + ListSelectionModel lsm = (ListSelectionModel) e.getSource(); + if (!lsm.isSelectionEmpty()) { + int minIndex = lsm.getMinSelectionIndex(); + int maxIndex = lsm.getMaxSelectionIndex(); + for (int i = minIndex; + i <= maxIndex; + i++) { + if (lsm.isSelectedIndex(i)) { + selectedWebcam = webcams.get(i); + closePanel(); + if (this.selectWencamListener != null) { + this.selectWencamListener.onSelect(selectedWebcam); + + } + break; + } + } + + this.selectDeviceTableModel.fireTableDataChanged(); + } + + } +} diff --git a/src/main/java/net/bither/viewsystem/froms/ShowTransactionsForm.java b/src/main/java/net/bither/viewsystem/froms/ShowTransactionsForm.java index ec0079e..0a9cd63 100644 --- a/src/main/java/net/bither/viewsystem/froms/ShowTransactionsForm.java +++ b/src/main/java/net/bither/viewsystem/froms/ShowTransactionsForm.java @@ -134,7 +134,7 @@ private void initUI() { panelMain.add(btnTxPanel, BorderLayout.SOUTH); if (AddressManager.getInstance().getAllAddresses().size() == 0 && - AddressManager.getInstance().getHdAccount() == null) { + AddressManager.getInstance().getHDAccountHot() == null) { showTransactionHeaderForm.setVisible(false); } else { showTransactionHeaderForm.setVisible(true); @@ -334,7 +334,7 @@ private void scrollPaneSetup() { @Override public void displayView(DisplayHint displayHint) { if (AddressManager.getInstance().getAllAddresses().size() == 0 && - AddressManager.getInstance().getHdAccount() == null) { + AddressManager.getInstance().getHDAccountHot() == null) { showTransactionHeaderForm.setVisible(false); } else { showTransactionHeaderForm.setVisible(true); diff --git a/src/main/java/net/bither/viewsystem/froms/desktop/hdm/DesktopHDMColdMsgPanel.java b/src/main/java/net/bither/viewsystem/froms/desktop/hdm/DesktopHDMColdMsgPanel.java new file mode 100644 index 0000000..f6b8931 --- /dev/null +++ b/src/main/java/net/bither/viewsystem/froms/desktop/hdm/DesktopHDMColdMsgPanel.java @@ -0,0 +1,101 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.viewsystem.froms.desktop.hdm; + +import com.github.sarxos.webcam.Webcam; +import net.bither.bitherj.core.AddressManager; +import net.bither.bitherj.core.DesktopHDMKeychain; +import net.bither.bitherj.crypto.SecureCharSequence; +import net.bither.bitherj.qrcode.QRCodeTxTransport; +import net.bither.bitherj.qrcode.QRCodeUtil; +import net.bither.bitherj.utils.Utils; +import net.bither.qrcode.DesktopQRCodReceive; +import net.bither.qrcode.DesktopQRCodSend; +import net.bither.viewsystem.dialogs.AbstractDesktopHDMMsgDialog; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public class DesktopHDMColdMsgPanel extends AbstractDesktopHDMMsgDialog { + + private SecureCharSequence password; + + public DesktopHDMColdMsgPanel(SecureCharSequence password, Webcam webcam) { + super(webcam); + isSendMode = false; + this.password = password; + } + + @Override + protected void handleScanResult(String result) { + + if (isSendMode) { + if (desktopQRCodSend != null) { + if (DesktopQRCodSend.getSendCodeFromMsg(result) > desktopQRCodSend.getSendCode()) { + if (desktopQRCodSend.sendFinish()) { + isSendMode = false; + desktopQRCodReceive = new DesktopQRCodReceive(); + } + } else { + desktopQRCodSend.setReceiveMsg(result); + if (desktopQRCodSend.canNextPage()) { + desktopQRCodSend.nextPage(); + showQRCode(desktopQRCodSend.getShowMessage()); + } + } + } + + } else { + if (desktopQRCodReceive != null) { + desktopQRCodReceive.receiveMsg(result); + showQRCode(desktopQRCodReceive.getShowMsg()); + if (desktopQRCodReceive.receiveComplete()) { + isSendMode = true; + desktopQRCodSend = new DesktopQRCodSend(getSignString()); + showQRCode(desktopQRCodSend.getShowMessage()); + } + } + } + + + } + + @Override + protected void inited() { + desktopQRCodReceive = new DesktopQRCodReceive(); + + } + + private String getSignString() { + String string = desktopQRCodReceive.getReceiveResult(); + QRCodeTxTransport qrCodeTransportPage = QRCodeTxTransport.formatQRCodeTransportOfDesktopHDM(string); + DesktopHDMKeychain desktopHDMKeychain = AddressManager.getInstance().getDesktopHDMKeychains().get(0); + List unsignHashs = new ArrayList(); + for (String str : qrCodeTransportPage.getHashList()) { + unsignHashs.add(Utils.hexStringToByteArray(str)); + } + List signatureList = desktopHDMKeychain.signWithCold(unsignHashs, password, qrCodeTransportPage.getPathTypeIndexes()); + List result = new ArrayList(); + for (byte[] signature : signatureList) { + result.add(Utils.bytesToHexString(signature).toUpperCase(Locale.US)); + } + return Utils.joinString(result, QRCodeUtil.QR_CODE_SPLIT); + } +} diff --git a/src/main/java/net/bither/viewsystem/froms/desktop/hdm/DesktopHDMColdPanel.java b/src/main/java/net/bither/viewsystem/froms/desktop/hdm/DesktopHDMColdPanel.java new file mode 100644 index 0000000..d269509 --- /dev/null +++ b/src/main/java/net/bither/viewsystem/froms/desktop/hdm/DesktopHDMColdPanel.java @@ -0,0 +1,270 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.viewsystem.froms.desktop.hdm; + +import com.github.sarxos.webcam.Webcam; +import net.bither.bitherj.core.AddressManager; +import net.bither.bitherj.core.DesktopHDMKeychain; +import net.bither.bitherj.crypto.SecureCharSequence; +import net.bither.bitherj.delegate.IPasswordGetterDelegate; +import net.bither.fonts.AwesomeIcon; +import net.bither.languages.MessageKey; +import net.bither.qrcode.DisplayBitherQRCodePanel; +import net.bither.utils.KeyUtil; +import net.bither.utils.LocaliserUtils; +import net.bither.viewsystem.base.Buttons; +import net.bither.viewsystem.base.Panels; +import net.bither.viewsystem.dialogs.DialogProgress; +import net.bither.viewsystem.dialogs.MessageDialog; +import net.bither.viewsystem.froms.PasswordPanel; +import net.bither.viewsystem.froms.SelectWebcamPanel; +import net.bither.viewsystem.froms.WizardPanel; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.List; + +public class DesktopHDMColdPanel extends WizardPanel implements IPasswordGetterDelegate, SelectWebcamPanel.ISelectWencamListener { + + private PasswordPanel.PasswordGetter passwordGetter; + private JButton btnAddHDMKeychain; + private JButton btnFirstMasterPub; + private JButton btnSecondMasterPub; + private JButton btnSignTransaction; + private JPanel panel; + private SecureCharSequence password; + + public DesktopHDMColdPanel() { + super(MessageKey.HDM, AwesomeIcon.FA_RECYCLE); + passwordGetter = new PasswordPanel.PasswordGetter(DesktopHDMColdPanel.this); + initUI(); + + + } + + private void initUI() { + + btnFirstMasterPub = Buttons.newNormalButton(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + final DialogProgress dp = new DialogProgress(); + new Thread(new Runnable() { + @Override + public void run() { + final SecureCharSequence password = passwordGetter.getPassword(); + if (password == null) { + return; + } + List desktopHDMKeychains = + AddressManager.getInstance().getDesktopHDMKeychains(); + if (desktopHDMKeychains == null || desktopHDMKeychains.size() == 0) { + return; + } + DesktopHDMKeychain desktopHDMKeychain = desktopHDMKeychains.get(0); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + dp.pack(); + dp.setVisible(true); + } + }); + final String extendPubkey = desktopHDMKeychain.getMasterPubKeyExtendedStr(password); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + dp.dispose(); + DisplayBitherQRCodePanel bitherQRCodePanel = + new DisplayBitherQRCodePanel(extendPubkey); + bitherQRCodePanel.showPanel(); + } + }); + + + } + }).start(); + + } + }, MessageKey.desktop_hdm_first_account, AwesomeIcon.HEADER); + btnSecondMasterPub = Buttons.newNormalButton(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + final DialogProgress dp = new DialogProgress(); + new Thread(new Runnable() { + @Override + public void run() { + final SecureCharSequence password = passwordGetter.getPassword(); + if (password == null) { + return; + } + List desktopHDMKeychains = + AddressManager.getInstance().getDesktopHDMKeychains(); + if (desktopHDMKeychains == null || desktopHDMKeychains.size() == 0) { + return; + } + DesktopHDMKeychain desktopHDMKeychain = desktopHDMKeychains.get(1); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + dp.pack(); + dp.setVisible(true); + } + }); + final String extendPubkey = desktopHDMKeychain.getMasterPubKeyExtendedStr(password); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + dp.dispose(); + DisplayBitherQRCodePanel bitherQRCodePanel = + new DisplayBitherQRCodePanel(extendPubkey); + bitherQRCodePanel.showPanel(); + } + }); + + + } + }).start(); + + + } + }, MessageKey.desktop_hdm_second_account, AwesomeIcon.HEADER); + btnSignTransaction = Buttons.newNormalButton(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + if (AddressManager.getInstance().getPrivKeyAddresses().size() == 0 && AddressManager.getInstance().getHdmKeychain() == null && !AddressManager.getInstance().hasDesktopHDMKeychain()) { + new MessageDialog(LocaliserUtils.getString("private_key_is_empty")).showMsg(); + } else { + new Thread(new Runnable() { + @Override + public void run() { + final SecureCharSequence secureCharSequence = passwordGetter.getPassword(); + if (secureCharSequence == null) { + return; + } + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + password = secureCharSequence; + SelectWebcamPanel selectWebcamPanel = new SelectWebcamPanel(DesktopHDMColdPanel.this); + selectWebcamPanel.showPanel(); + } + }); + + + } + }).start(); + } + } + }, MessageKey.SIGN_TX, AwesomeIcon.PENCIL); + btnAddHDMKeychain = Buttons.newNormalButton(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + new Thread(new Runnable() { + @Override + public void run() { + final SecureCharSequence password = passwordGetter.getPassword(); + if (password == null) { + return; + } + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + // closePanel(); +// if (xrandomCheckBox.isSelected()) { +// HDMKeychainColdUEntropyDialog hdmKeychainColdUEntropyDialog = new HDMKeychainColdUEntropyDialog(passwordGetter); +// hdmKeychainColdUEntropyDialog.pack(); +// hdmKeychainColdUEntropyDialog.setVisible(true); +// } else { + List desktopHDMKeychainList = new ArrayList(); + DesktopHDMKeychain chain1 = new DesktopHDMKeychain(new SecureRandom(), password); + desktopHDMKeychainList.add(chain1); + DesktopHDMKeychain chain2 = new DesktopHDMKeychain(new SecureRandom(), password); + desktopHDMKeychainList.add(chain2); + KeyUtil.setDesktopHMDKeychains(desktopHDMKeychainList); + passwordGetter.wipe(); + refreshPanel(); + + + // } + } + }); + + } + }).start(); + + } + }, MessageKey.add_desktop_hdm_cold_keychain, AwesomeIcon.PLUS); + + } + + @Override + public void initialiseContent(JPanel panel) { + this.panel = panel; + refreshPanel(); + } + + @Override + public void closePanel() { + super.closePanel(); + if (passwordGetter != null) { + passwordGetter.wipe(); + } + } + + private void refreshPanel() { + panel.removeAll(); + panel.setLayout(new MigLayout( + Panels.migXYLayout(), + "[][][][][][][]", // Column constraints + "[][][][][][]" // Row constraints + )); + + + if (AddressManager.getInstance().hasDesktopHDMKeychain()) { + panel.add(btnFirstMasterPub, "align center,cell 3 0 ,shrink,wrap"); + panel.add(btnSecondMasterPub, "align center,cell 3 1 ,shrink,wrap"); + panel.add(btnSignTransaction, "align center,cell 3 2 ,shrink,wrap"); + } else { + panel.add(btnAddHDMKeychain, "align center,cell 3 0 ,shrink,wrap"); + } + + } + + @Override + public void beforePasswordDialogShow() { + + } + + @Override + public void afterPasswordDialogDismiss() { + + } + + @Override + public void onSelect(Webcam webcam) { + if (webcam != null) { + DesktopHDMColdMsgPanel desktopHDMColdMsgPanel = new DesktopHDMColdMsgPanel(password, webcam); + desktopHDMColdMsgPanel.pack(); + desktopHDMColdMsgPanel.setVisible(true); + } + + } +} diff --git a/src/main/java/net/bither/viewsystem/froms/desktop/hdm/DesktopHDMHotPanel.java b/src/main/java/net/bither/viewsystem/froms/desktop/hdm/DesktopHDMHotPanel.java new file mode 100644 index 0000000..aafd372 --- /dev/null +++ b/src/main/java/net/bither/viewsystem/froms/desktop/hdm/DesktopHDMHotPanel.java @@ -0,0 +1,324 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.viewsystem.froms.desktop.hdm; + +import com.github.sarxos.webcam.Webcam; +import net.bither.bitherj.core.AddressManager; +import net.bither.bitherj.core.DesktopHDMKeychain; +import net.bither.bitherj.core.Tx; +import net.bither.bitherj.crypto.SecureCharSequence; +import net.bither.bitherj.delegate.IPasswordGetterDelegate; +import net.bither.bitherj.qrcode.QRCodeUtil; +import net.bither.bitherj.utils.UnitUtil; +import net.bither.bitherj.utils.Utils; +import net.bither.fonts.AwesomeIcon; +import net.bither.implbitherj.TxNotificationCenter; +import net.bither.languages.MessageKey; +import net.bither.qrcode.DisplayQRCodePanle; +import net.bither.qrcode.IReadQRCode; +import net.bither.qrcode.IScanQRCode; +import net.bither.qrcode.SelectQRCodePanel; +import net.bither.utils.KeyUtil; +import net.bither.utils.LocaliserUtils; +import net.bither.viewsystem.base.Buttons; +import net.bither.viewsystem.base.Labels; +import net.bither.viewsystem.base.Panels; +import net.bither.viewsystem.dialogs.DialogProgress; +import net.bither.viewsystem.froms.PasswordPanel; +import net.bither.viewsystem.froms.SelectWebcamPanel; +import net.bither.viewsystem.froms.WizardPanel; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.List; + +public class DesktopHDMHotPanel extends WizardPanel implements IPasswordGetterDelegate, TxNotificationCenter.ITxListener, SelectWebcamPanel.ISelectWencamListener { + + private PasswordPanel.PasswordGetter passwordGetter; + + private JButton btnImportFirstMasterPub; + private JButton btnImportSecondMasterPub; + + private JButton btnAddKeychain; + + private JButton btnAddress; + private JButton btnSignTx; + + private JLabel labelBanlance; + + private byte[] bytesFirst = null; + private byte[] bytesSecond = null; + private JPanel panel; + private SecureCharSequence password; + + + public DesktopHDMHotPanel() { + super(MessageKey.HDM, AwesomeIcon.FA_RECYCLE); + passwordGetter = new PasswordPanel.PasswordGetter(DesktopHDMHotPanel.this); + TxNotificationCenter.addTxListener(DesktopHDMHotPanel.this); + + ininPubKeyUI(); + initAddKeychain(); + initAddress(); + + } + + private void initAddKeychain() { + btnAddKeychain = Buttons.newNormalButton(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + + new Thread(new Runnable() { + @Override + public void run() { + final SecureCharSequence password = passwordGetter.getPassword(); + if (password == null) { + return; + } + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + // closePanel(); +// if (xrandomCheckBox.isSelected()) { +// HDMKeychainColdUEntropyDialog hdmKeychainColdUEntropyDialog = new HDMKeychainColdUEntropyDialog(passwordGetter); +// hdmKeychainColdUEntropyDialog.pack(); +// hdmKeychainColdUEntropyDialog.setVisible(true); +// } else { + DesktopHDMKeychain chain = new DesktopHDMKeychain(new SecureRandom(), password); + List desktopHDMKeychainList = new ArrayList(); + desktopHDMKeychainList.add(chain); + KeyUtil.setDesktopHMDKeychains(desktopHDMKeychainList); + password.wipe(); + refreshPanel(); + // Bither.refreshFrame(); + + + // } + } + }); + + } + }).start(); + + + } + }, MessageKey.add_desktop_hdm_hot_keychain, AwesomeIcon.PLUS); + + } + + private void initAddress() { + labelBanlance = Labels.newValueLabel(""); + btnAddress = Buttons.newNormalButton(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (!AddressManager.getInstance().hasDesktopHDMKeychain()) { + return; + } + DesktopHDMKeychain hdmKeychain = AddressManager.getInstance().getDesktopHDMKeychains().get(0); + DisplayQRCodePanle displayQRCodePanle = new DisplayQRCodePanle(hdmKeychain.externalAddress()); + displayQRCodePanle.showPanel(); + + } + }, MessageKey.address, AwesomeIcon.QRCODE); + btnSignTx = Buttons.newNormalButton(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + new Thread(new Runnable() { + @Override + public void run() { + final SecureCharSequence secureCharSequence = passwordGetter.getPassword(); + if (secureCharSequence == null) { + return; + } + password = secureCharSequence; + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + SelectWebcamPanel selectWebcamPanel = new SelectWebcamPanel(DesktopHDMHotPanel.this); + selectWebcamPanel.showPanel(); + + + } + }); + + + } + }).start(); + + + } + }, MessageKey.SIGN_TX, AwesomeIcon.PENCIL); + + } + + private void ininPubKeyUI() { + btnImportFirstMasterPub = Buttons.newNormalButton(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + SelectQRCodePanel selectQRCodePanel = new SelectQRCodePanel(new IScanQRCode() { + @Override + public void handleResult(String result, IReadQRCode readQRCode) { + readQRCode.close(); + if (QRCodeUtil.verifyBitherQRCode(result)) { + bytesFirst = Utils.hexStringToByteArray(result); + btnImportFirstMasterPub.setEnabled(true); + addOtherPubkey(); + } else { + readQRCode.reTry(""); + } + + } + }); + selectQRCodePanel.showPanel(); + + } + }, MessageKey.import_desktop_hdm_first_account, AwesomeIcon.FA_SIGN_IN); + btnImportSecondMasterPub = Buttons.newNormalButton(new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + SelectQRCodePanel selectQRCodePanel = new SelectQRCodePanel(new IScanQRCode() { + @Override + public void handleResult(String result, IReadQRCode readQRCode) { + readQRCode.close(); + if (QRCodeUtil.verifyBitherQRCode(result)) { + bytesSecond = Utils.hexStringToByteArray(result); + btnImportSecondMasterPub.setEnabled(true); + addOtherPubkey(); + } else { + readQRCode.reTry(""); + } + + } + }); + selectQRCodePanel.showPanel(); + + } + }, MessageKey.import_desktop_hdm_second_account, AwesomeIcon.FA_SIGN_IN); + } + + private void addOtherPubkey() { + if (bytesSecond == null || bytesFirst == null || !AddressManager.getInstance().hasDesktopHDMKeychain()) { + return; + } + final DialogProgress dialogProgress = new DialogProgress(); + + new Thread(new Runnable() { + @Override + public void run() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + dialogProgress.pack(); + dialogProgress.setVisible(true); + } + }); + DesktopHDMKeychain desktopHDMKeychain = + AddressManager.getInstance().getDesktopHDMKeychains().get(0); + desktopHDMKeychain.addAccountKey(bytesFirst, bytesSecond); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + refreshPanel(); + dialogProgress.dispose(); + } + }); + + } + }).start(); + + + } + + + private void refreshPanel() { + panel.removeAll(); + panel.setLayout(new MigLayout( + Panels.migXYLayout(), + "[][][][][][][]", // Column constraints + "[][][][][][]" // Row constraints + )); + + if (AddressManager.getInstance().hasDesktopHDMKeychain()) { + DesktopHDMKeychain desktopHDMKeychain = AddressManager.getInstance().getDesktopHDMKeychains().get(0); + if (desktopHDMKeychain.hasDesktopHDMAddress()) { + panel.add(labelBanlance, "align center,cell 3 0 ,shrink,wrap"); + panel.add(btnAddress, "align center,cell 3 1 ,shrink,wrap"); + panel.add(btnSignTx, "align center,cell 3 2 ,shrink,wrap"); + refreshBanlance(); + } else { + panel.add(btnImportFirstMasterPub, "align center,cell 3 0 ,shrink,wrap"); + panel.add(btnImportSecondMasterPub, "align center,cell 3 1 ,shrink,wrap"); + } + } else { + panel.add(btnAddKeychain, "align center,cell 3 0 ,shrink,wrap"); + } + + } + + private void refreshBanlance() { + if (AddressManager.getInstance().hasDesktopHDMKeychain()) { + DesktopHDMKeychain desktopHDMKeychain = AddressManager.getInstance().getDesktopHDMKeychains().get(0); + labelBanlance.setText(LocaliserUtils.getString("send_confirm_amount") + UnitUtil.formatValue(desktopHDMKeychain.getBalance(), UnitUtil.BitcoinUnit.BTC)); + } + + } + + @Override + public void initialiseContent(JPanel panel) { + this.panel = panel; + refreshPanel(); + + + } + + @Override + public void beforePasswordDialogShow() { + + } + + @Override + public void afterPasswordDialogDismiss() { + + } + + @Override + public void notificatTx(String address, Tx tx, Tx.TxNotificationType txNotificationType, long deltaBalance) { + refreshBanlance(); + } + + @Override + public void closePanel() { + super.closePanel(); + TxNotificationCenter.removeTxListener(DesktopHDMHotPanel.this); + } + + @Override + public void onSelect(Webcam webcam) { + if (webcam != null) { + DesktopHDMMsgHotDialog desktopHDMHotMsgPanel = new DesktopHDMMsgHotDialog(password, webcam); + desktopHDMHotMsgPanel.pack(); + desktopHDMHotMsgPanel.setVisible(true); + } + + + } +} diff --git a/src/main/java/net/bither/viewsystem/froms/desktop/hdm/DesktopHDMMsgHotDialog.java b/src/main/java/net/bither/viewsystem/froms/desktop/hdm/DesktopHDMMsgHotDialog.java new file mode 100644 index 0000000..a61036c --- /dev/null +++ b/src/main/java/net/bither/viewsystem/froms/desktop/hdm/DesktopHDMMsgHotDialog.java @@ -0,0 +1,313 @@ +/* + * + * Copyright 2014 http://Bither.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * / + */ + +package net.bither.viewsystem.froms.desktop.hdm; + +import com.github.sarxos.webcam.Webcam; +import net.bither.bitherj.core.*; +import net.bither.bitherj.crypto.ECKey; +import net.bither.bitherj.crypto.SecureCharSequence; +import net.bither.bitherj.crypto.TransactionSignature; +import net.bither.bitherj.db.AbstractDb; +import net.bither.bitherj.qrcode.QRCodeUtil; +import net.bither.bitherj.utils.Utils; +import net.bither.qrcode.DesktopQRCodReceive; +import net.bither.qrcode.DesktopQRCodSend; +import net.bither.runnable.CommitTransactionThread; +import net.bither.runnable.CompleteTransactionRunnable; +import net.bither.utils.FileUtil; +import net.bither.utils.WalletUtils; +import net.bither.viewsystem.dialogs.AbstractDesktopHDMMsgDialog; +import net.bither.viewsystem.dialogs.MessageDialog; + +import javax.swing.*; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class DesktopHDMMsgHotDialog extends AbstractDesktopHDMMsgDialog { + + + static { + WalletUtils.initTxBuilderException(); + } + + private static final long CHECK_TX_INTERVAL = 3 * 1000; + + private Tx tx; + +// private List> addressAmtList = new ArrayList>(); + private HashMap sendingRequest = null; +// private File addressAmtFile; + private SecureCharSequence password; + private DesktopHDMKeychain desktopHDMKeychain; + + + public DesktopHDMMsgHotDialog(SecureCharSequence password, Webcam webcam) { + super(webcam); + isSendMode = true; + this.password = password; + desktopHDMKeychain = AddressManager.getInstance().getDesktopHDMKeychains().get(0); + } + + @Override + public void handleScanResult(final String result) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (isSendMode) { + if (desktopQRCodSend != null) { + + if (DesktopQRCodSend.getSendCodeFromMsg(result) > desktopQRCodSend.getSendCode()) { + if (desktopQRCodSend.sendFinish()) { + isSendMode = false; + desktopQRCodReceive = new DesktopQRCodReceive(); + + } + } else { + if (desktopQRCodSend != null) { + desktopQRCodSend.setReceiveMsg(result); + } + if (desktopQRCodSend.canNextPage()) { + desktopQRCodSend.nextPage(); + showQRCode(desktopQRCodSend.getShowMessage()); + + } + } + } + } else { + if (desktopQRCodReceive != null) { + desktopQRCodReceive.receiveMsg(result); + showQRCode(desktopQRCodReceive.getShowMsg()); + if (desktopQRCodSend.sendFinish() && desktopQRCodReceive.receiveComplete()) { + publishTx(); + + } + } + } + + } + }); + + } + + public void publishTx() { + String signStr = desktopQRCodReceive.getReceiveResult(); + String[] signs = QRCodeUtil.splitString(signStr); + final List transactionSignatureList = new ArrayList(); + for (String str : signs) { + byte[] bytes = Utils.hexStringToByteArray(str); + TransactionSignature transactionSignature = new TransactionSignature(ECKey + .ECDSASignature.decodeFromDER(bytes), TransactionSignature.SigHash + .ALL, false); + transactionSignatureList.add(transactionSignature); + } + final List desktopHDMAddresses = desktopHDMKeychain.getSigningAddressesForInputs(tx.getIns()); + List unSignHash = new ArrayList(); + List unSignDesktopHDMAddress = new ArrayList(); + for (int i = 0; i < desktopHDMAddresses.size(); i++) { + DesktopHDMAddress a = desktopHDMAddresses.get(i); + for (byte[] h : tx.getUnsignedInHashesForDesktpHDM(a.getPubKey(), i)) { + unSignHash.add(h); + unSignDesktopHDMAddress.add(a); + } + } + // System.out.println("unSign:" + Utils.bytesToHexString(unSignHash.get(0))); + desktopHDMKeychain.signTx(tx, unSignHash, password, unSignDesktopHDMAddress, new DesktopHDMKeychain.DesktopHDMFetchOtherSignatureDelegate() { + @Override + public List getOtherSignature(Tx tx, List unsignHash, List pathTypeIndexLsit) { + return transactionSignatureList; + } + }); + if (!tx.verifySignatures()) { + System.out.println("tx verify failed"); + return; + } + try { + CommitTransactionThread commitTransactionThread = new CommitTransactionThread(null, tx, false, new CommitTransactionThread.CommitTransactionListener() { + @Override + public void onCommitTransactionSuccess(Tx tx) { +// synchronized (addressAmtList) { +// isSendMode = true; +// if (addressAmtList.size() > 0) { +// addressAmtList.remove(0); +// saveFile(addressAmtList, addressAmtFile); +// } + + if (sendingRequest != null) { + desktopHDMKeychain.getSendRequestList().remove(sendingRequest); + } + desktopQRCodReceive = null; + desktopQRCodSend = null; +// } + } + + @Override + public void onCommitTransactionFailed() { + + } + }); + commitTransactionThread.start(); + } catch (Exception e) { + e.printStackTrace(); + } + + + } + + @Override + protected void inited() { + refreshTx(); + } + + private void refreshTx() { + new Thread(new Runnable() { + @Override + public void run() { + while (isRunning) { + try { + if (desktopQRCodSend == null) { + try { + getTx(); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + labMsg.setText(""); + } + }); + } catch (Exception e) { + e.printStackTrace(); + final String msg = CompleteTransactionRunnable.getMessageFromException(e); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + labMsg.setText(msg); + } + }); + } + } + Thread.sleep(CHECK_TX_INTERVAL); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + } + }).start(); + } + + private void getTx() throws Exception { + + if (desktopQRCodSend != null) { + return; + } +// if (addressAmtList.size() == 0) { +// addressAmtFile = getSendBitcoinFile(); +// +// addressAmtList = getAddressAndAmts(addressAmtFile); +// } + String address = null; + long amt; + + while (this.desktopHDMKeychain.getSendRequestList().size() > 0) { + HashMap hashMap = this.desktopHDMKeychain.getSendRequestList().peek(); + sendingRequest = hashMap; +// for (HashMap hashMap : addressAmtList) { + for (Map.Entry kv : hashMap.entrySet()) { + address = kv.getKey(); + amt = kv.getValue(); + String changeAddress = desktopHDMKeychain.getNewChangeAddress(); + tx = desktopHDMKeychain.newTx(address, amt); + + List signingAddresses = desktopHDMKeychain.getSigningAddressesForInputs(tx.getIns()); + isSendMode = true; + desktopQRCodSend = new DesktopQRCodSend(tx, signingAddresses, changeAddress); + showQRCode(desktopQRCodSend.getShowMessage()); + return; + } +// } + } + } + + private void saveFile(List> list, File file) { + try { + String result = ""; + for (HashMap hashMap : list) { + for (Map.Entry kv : hashMap.entrySet()) { + result = result + kv.getKey() + "," + Long.toString(kv.getValue()) + "\n"; + } + } + if (file.exists()) { + file.delete(); + } + if (list.size() > 0) { + Utils.writeFile(result.getBytes(), file); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + +// private List> getAddressAndAmts(File file) { +// if (file != null) { +// String content = Utils.readFile(file); +// if (Utils.isEmpty(content)) { +// if (file.exists()) { +// file.delete(); +// } +// } +// String[] addrssAndAmts = content.split("\n"); +// if (addrssAndAmts.length == 0) { +// if (file.exists()) { +// file.delete(); +// } +// } +// for (String str : addrssAndAmts) { +// String[] temp = str.split(","); +// if (temp.length > 1) { +// if (Utils.validBicoinAddress(temp[0])) { +// HashMap hashMap = new HashMap(); +// hashMap.put(temp[0], Long.valueOf(temp[1])); +// addressAmtList.add(hashMap); +// } +// } +// } +// if (addressAmtList.size() == 0) { +// if (file.exists()) { +// file.delete(); +// } +// } +// +// } +// return addressAmtList; +// +// +// } + + private File getSendBitcoinFile() { + File file = FileUtil.getSendBitcoinDir(); + File[] files = file.listFiles(); + if (files != null && files.length > 0) { + return files[0]; + } else { + return null; + } + } + +} diff --git a/src/main/java/net/bither/viewsystem/panels/WalletListPanel.java b/src/main/java/net/bither/viewsystem/panels/WalletListPanel.java index 88d4fb2..f17accb 100755 --- a/src/main/java/net/bither/viewsystem/panels/WalletListPanel.java +++ b/src/main/java/net/bither/viewsystem/panels/WalletListPanel.java @@ -161,9 +161,9 @@ private JPanel createWalletListPanel() { } } else { - if (AddressManager.getInstance().getHdAccount() != null) { + if (AddressManager.getInstance().getHDAccountHot() != null) { addPanel(constraints, LocaliserUtils.getString("add_hd_account_tab_hd")); - addHDAccountAddressList(constraints, AddressManager.getInstance().getHdAccount()); + addHDAccountAddressList(constraints, AddressManager.getInstance().getHDAccountHot()); } if (AddressManager.getInstance().hasHDMKeychain()) { @@ -183,8 +183,8 @@ private JPanel createWalletListPanel() { addHotAddressList(constraints, AddressManager.getInstance().getWatchOnlyAddresses()); } - if (AddressManager.getInstance().hasHDAccount()) { - activeAddress = AddressManager.getInstance().getHdAccount().getAddress(); + if (AddressManager.getInstance().hasHDAccountHot()) { + activeAddress = AddressManager.getInstance().getHDAccountHot().getAddress(); } else if (AddressManager.getInstance().hasHDMKeychain() && AddressManager.getInstance().getHdmKeychain().getAllCompletedAddresses().size() > 0) { activeAddress = AddressManager.getInstance().getHdmKeychain().getAllCompletedAddresses().get(0).getAddress(); } else if (AddressManager.getInstance().getPrivKeyAddresses().size() > 0) { diff --git a/src/main/java/net/bither/xrandom/PrivateKeyUEntropyDialog.java b/src/main/java/net/bither/xrandom/PrivateKeyUEntropyDialog.java index 8d81529..3d69e40 100644 --- a/src/main/java/net/bither/xrandom/PrivateKeyUEntropyDialog.java +++ b/src/main/java/net/bither/xrandom/PrivateKeyUEntropyDialog.java @@ -125,7 +125,7 @@ public void run() { // start encrypt ecKey = PrivateKeyUtil.encrypt(ecKey, password); Address address = new Address(ecKey.toAddress(), ecKey.getPubKey(), - PrivateKeyUtil.getEncryptedString(ecKey), ecKey.isFromXRandom()); + PrivateKeyUtil.getEncryptedString(ecKey), true, ecKey.isFromXRandom()); ecKey.clearPrivateKey(); addressList.add(address); addressStrs.add(address.getAddress()); diff --git a/src/main/resources/viewer.properties b/src/main/resources/viewer.properties index dfedd6e..fe14f4b 100755 --- a/src/main/resources/viewer.properties +++ b/src/main/resources/viewer.properties @@ -114,8 +114,10 @@ qr_code_form_camera=From Camera setting_name_transaction_fee=Default Transaction Fee -setting_name_transaction_fee_normal=Normal -setting_name_transaction_fee_low=Low +setting_name_transaction_fee_normal=Normal(0.1mBTC/kb) +setting_name_transaction_fee_high=High(0.2mBTC/kb) +setting_name_transaction_fee_higher=Higher(0.5mBTC/kb) +setting_name_transaction_fee_times10=10 Times(1.0mBTC/kb) setting_name_transaction_fee_normal_note=fast confirmation setting_name_transaction_fee_low_note=slow confirmation @@ -624,3 +626,13 @@ thread_count=Thread count compressed_private_key=Compressed Private Key vanity_address_option=Vanity Address Option +add_desktop_hdm_cold_keychain=Add Enterprise HDM (Cold) +add_desktop_hdm_hot_keychain=Add Enterprise HDM (Hot)\ +desktop_enterprise_hdm=Enterprise HDM +desktop_hdm_first_account=First Account +desktop_hdm_second_account=Second Account +import_desktop_hdm_first_account=Import First Account +import_desktop_hdm_second_account=Import Second Account + +select_camera=Select the camera + diff --git a/src/main/resources/viewer_zh_CN.properties b/src/main/resources/viewer_zh_CN.properties index 55d5799..adc4f3c 100755 --- a/src/main/resources/viewer_zh_CN.properties +++ b/src/main/resources/viewer_zh_CN.properties @@ -114,8 +114,10 @@ qr_code_form_camera=\u6444\u50cf\u5934 setting_name_transaction_fee=\u9ed8\u8ba4\u624b\u7eed\u8d39 -setting_name_transaction_fee_normal=\u6b63\u5e38 -setting_name_transaction_fee_low=\u8f83\u4f4e +setting_name_transaction_fee_normal=\u6b63\u5e38\u0028\u0030\u002e\u0031\u006d\u0042\u0054\u0043\u002f\u006b\u0062\u0029 +setting_name_transaction_fee_high=\u9ad8\u0028\u0030\u002e\u0032\u006d\u0042\u0054\u0043\u002f\u006b\u0062\u0029 +setting_name_transaction_fee_higher=\u66f4\u9ad8\u0028\u0030\u002e\u0035\u006d\u0042\u0054\u0043\u002f\u006b\u0062\u0029 +setting_name_transaction_fee_times10=\u0031\u0030\u500d\u0028\u0031\u002e\u0030\u006d\u0042\u0054\u0043\u002f\u006b\u0062\u0029 setting_name_transaction_fee_normal_note=\u8f83\u5feb\u786e\u8ba4 setting_name_transaction_fee_low_note=\u8f83\u6162\u786e\u8ba4 @@ -620,4 +622,15 @@ hd_account_xrandom_final_confirm=\u60a8\u751f\u6210\u4e86\u4e00\u4e2a\u6781\u968 thread_count=\u7ebf\u7a0b\u6570 compressed_private_key=\u538b\u7f29\u683c\u5f0f\u79c1\u94a5 -vanity_address_option=\u8363\u8000\u5730\u5740\u9009\u9879 \ No newline at end of file +vanity_address_option=\u8363\u8000\u5730\u5740\u9009\u9879 + +add_desktop_hdm_cold_keychain=\u6dfb\u52a0\u4f01\u4e1aHDM (\u51b7) +add_desktop_hdm_hot_keychain=\u6dfb\u52a0\u4f01\u4e1aHDM (\u70ed) + +desktop_enterprise_hdm=\u4f01\u4e1a HDM +desktop_hdm_first_account=\u51b7\u8d26\u6237\u4e00 +desktop_hdm_second_account=\u51b7\u8d26\u6237\u4e8c +import_desktop_hdm_first_account=\u5bfc\u5165\u51b7\u8d26\u6237\u4e00 +import_desktop_hdm_second_account=\u5bfc\u5165\u51b7\u8d26\u6237\u4e8c + +select_camera=\u9009\u62e9\u6444\u50cf\u5934 \ No newline at end of file diff --git a/src/main/resources/viewer_zh_TW.properties b/src/main/resources/viewer_zh_TW.properties index 7a459f0..54b0e00 100755 --- a/src/main/resources/viewer_zh_TW.properties +++ b/src/main/resources/viewer_zh_TW.properties @@ -114,8 +114,10 @@ qr_code_form_camera=\u651d\u50cf\u982d setting_name_transaction_fee=\u9ed8\u8a8d\u624b\u7e8c\u8cbb -setting_name_transaction_fee_normal=\u6b63\u5e38 -setting_name_transaction_fee_low=\u8f03\u4f4e +setting_name_transaction_fee_normal=\u6b63\u5e38\u0028\u0030\u002e\u0031\u006d\u0042\u0054\u0043\u002f\u006b\u0062\u0029 +setting_name_transaction_fee_high=\u9ad8\u0028\u0030\u002e\u0032\u006d\u0042\u0054\u0043\u002f\u006b\u0062\u0029 +setting_name_transaction_fee_higher=\u66f4\u9ad8\u0028\u0030\u002e\u0035\u006d\u0042\u0054\u0043\u002f\u006b\u0062\u0029 +setting_name_transaction_fee_times10=\u0031\u0030\u500d\u0028\u0031\u002e\u0030\u006d\u0042\u0054\u0043\u002f\u006b\u0062\u0029 setting_name_transaction_fee_normal_note=\u8f03\u5feb\u78ba\u8a8d setting_name_transaction_fee_low_note=\u8f03\u6162\u78ba\u8a8d @@ -624,4 +626,16 @@ hd_account_xrandom_final_confirm\u60a8\u751f\u6210\u4e86\u4e00\u500b\u6975\u96a8 thread_count=\u7dda\u7a0b\u6578 compressed_private_key=\u58d3\u7e2e\u683c\u5f0f\u79c1\u9470 -vanity_address_option=\u69ae\u8000\u5730\u5740\u9078\u9805 \ No newline at end of file +vanity_address_option=\u69ae\u8000\u5730\u5740\u9078\u9805 + + +add_desktop_hdm_cold_keychain=\u6dfb\u52a0\u4f01\u696dHDM (\u51b7) +add_desktop_hdm_hot_keychain=\u6dfb\u52a0\u4f01\u696dHDM (\u71b1) + +desktop_enterprise_hdm=\u4f01\u696d HDM +desktop_hdm_first_account=\u51b7\u8cec\u6236\u4e00 +desktop_hdm_second_account=\u51b7\u8cec\u6236\u4e8c +import_desktop_hdm_first_account=\u5c0e\u5165\u51b7\u8cec\u6236\u4e00 +import_desktop_hdm_second_account=\u5c0e\u5165\u51b7\u8cec\u6236\u4e8c + +select_camera=\u9078\u64c7\u651d\u50cf\u982d \ No newline at end of file diff --git a/vanitygen/windows/libeay32.dll b/vanitygen/windows/libeay32.dll new file mode 100644 index 0000000..7adefd1 Binary files /dev/null and b/vanitygen/windows/libeay32.dll differ diff --git a/vanitygen/windows/msvcr100.dll b/vanitygen/windows/msvcr100.dll new file mode 100644 index 0000000..b1c3a5e Binary files /dev/null and b/vanitygen/windows/msvcr100.dll differ diff --git a/vanitygen/windows/oclvanitygen64.exe b/vanitygen/windows/oclvanitygen64.exe index 5aa9dc1..ecb045e 100644 Binary files a/vanitygen/windows/oclvanitygen64.exe and b/vanitygen/windows/oclvanitygen64.exe differ diff --git a/vanitygen/windows/vanitygen64.exe b/vanitygen/windows/vanitygen64.exe index 70a7cac..5793e30 100644 Binary files a/vanitygen/windows/vanitygen64.exe and b/vanitygen/windows/vanitygen64.exe differ