Skip to content

Commit

Permalink
new wallet file forms
Browse files Browse the repository at this point in the history
  • Loading branch information
fireduck64 committed Jul 6, 2018
1 parent 57bd4e4 commit 6eb6aa0
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 33 deletions.
27 changes: 4 additions & 23 deletions client/src/SnowBlossomClient.java
Expand Up @@ -154,35 +154,16 @@ public void send(long value, String to)
public void loadWallet()
throws Exception
{
wallet_path.mkdirs();

File db_file = new File(wallet_path, "wallet.db");
if (db_file.exists())
{
wallet_database = WalletDatabase.parseFrom(new FileInputStream(db_file));
}
else
wallet_database = WalletUtil.loadWallet(wallet_path, true);
if (wallet_database == null)
{
logger.log(Level.WARNING, String.format("File %s does not exist, creating new wallet", db_file.getPath()));
logger.log(Level.WARNING, String.format("Directory %s does not contain wallet, creating new wallet", wallet_path.getPath()));
wallet_database = WalletUtil.makeNewDatabase(config);
saveWallet();
WalletUtil.saveWallet(wallet_database, wallet_path);
}

}

public void saveWallet()
throws Exception
{
File db_file = new File(wallet_path, "wallet.db");
AtomicFileOutputStream out = new AtomicFileOutputStream(db_file);

wallet_database.writeTo(out);
out.flush();
out.close();

logger.log(Level.INFO, String.format("Save to file %s completed", db_file.getPath()));
}

public void showBalances()
{
long total_confirmed = 0;
Expand Down
139 changes: 132 additions & 7 deletions client/src/WalletUtil.java
Expand Up @@ -2,24 +2,37 @@

import com.google.common.collect.ImmutableList;
import duckutil.Config;
import duckutil.AtomicFileOutputStream;
import snowblossom.lib.AddressUtil;
import snowblossom.lib.KeyUtil;
import snowblossom.proto.AddressSpec;
import snowblossom.proto.WalletDatabase;
import snowblossom.proto.WalletKeyPair;
import snowblossom.proto.*;

import com.google.protobuf.ByteString;


import java.util.logging.Logger;
import java.util.logging.Level;
import java.io.File;
import java.io.FileInputStream;
import java.util.HashSet;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.LinkedList;
import snowblossom.lib.HexUtil;

public class WalletUtil
{
public static final String MODE_STANDARD = "standard";
public static final String MODE_QHARD = "qhard";

private static final Logger logger = Logger.getLogger("snowblossom.client");
public static final int WALLET_DB_VERSION = 2;

public static WalletDatabase makeNewDatabase(Config config)
{
WalletDatabase.Builder builder = WalletDatabase.newBuilder();
builder.setVersion(WALLET_DB_VERSION);

int count = config.getIntWithDefault("key_count", 8);
for (int i = 0; i < count; i++)
Expand All @@ -36,7 +49,6 @@ public static void genNewKey(WalletDatabase.Builder wallet_builder, Config confi

if (key_mode.equals(MODE_STANDARD))
{

WalletKeyPair wkp = KeyUtil.generateWalletStandardECKey();
wallet_builder.addKeys(wkp);
AddressSpec claim = AddressUtil.getSimpleSpecForKey(wkp);
Expand All @@ -55,12 +67,125 @@ else if (key_mode.equals(MODE_QHARD))

AddressSpec claim = AddressUtil.getMultiSig(3, ImmutableList.of(k_ec, k_rsa, k_dstu));
wallet_builder.addAddresses(claim);


}
else
{
throw new RuntimeException("Unknown key_mode: " + key_mode);
}
}
}

public static WalletDatabase loadWallet(File wallet_path, boolean cleanup)
throws Exception
{
if (!wallet_path.isDirectory()) return null;

LinkedList<File> files_to_read = new LinkedList<>();

{ // old wallet.db file
File old_file = new File(wallet_path, "wallet.db");
if (old_file.exists()) files_to_read.add(old_file);
}
for(File f : wallet_path.listFiles())
{
if (f.getName().endsWith(".wallet"))
{
files_to_read.add(f);
}
}

LinkedList<File> files_to_delete_on_cleanup=new LinkedList<>();
LinkedList<WalletDatabase> found_db_list=new LinkedList<>();
for(File f : files_to_read)
{
FileInputStream fin = new FileInputStream(f);
WalletDatabase w = WalletDatabase.parseFrom(fin);
fin.close();

found_db_list.add(w);
if (w.getVersion() <= WALLET_DB_VERSION)
{
files_to_delete_on_cleanup.add(f);
}
else
{
if (cleanup)
{
logger.info(String.format("Wallet db version %d for %s is newer than this code, so can't re-write it. This is safe, but might lead to file clutter long term.", w.getVersion(), f.getPath()));
}
}

}

if (found_db_list.size() > 0)
{
WalletDatabase merged = mergeDatabases(found_db_list);

if ((cleanup) && (found_db_list.size() > 1))
{
saveWallet(merged, wallet_path);
for(File f : files_to_delete_on_cleanup)
{
f.delete();
}
}

return merged;
}


return null;
}

public static WalletDatabase mergeDatabases(List<WalletDatabase> src_list)
{
WalletDatabase.Builder new_db = WalletDatabase.newBuilder();

new_db.setVersion(WALLET_DB_VERSION);
HashSet<WalletKeyPair> key_set=new HashSet<>();
HashSet<AddressSpec> address_set =new HashSet<>();
HashSet<Transaction> tx_set = new HashSet<>();
HashMap<String, Boolean> used_addresses = new HashMap<>();
HashMap<String, Long> address_create_time = new HashMap<>();

for(WalletDatabase src : src_list)
{
key_set.addAll(src.getKeysList());
address_set.addAll(src.getAddressesList());
tx_set.addAll(src.getTransactionsList());

used_addresses.putAll(src.getUsedAddressesMap());
address_create_time.putAll(src.getAddressCreateTimeMap());
}

new_db.addAllKeys(key_set);
new_db.addAllAddresses(address_set);
new_db.addAllTransactions(tx_set);
new_db.putAllUsedAddresses(used_addresses);
new_db.putAllAddressCreateTime(address_create_time);

return new_db.build();
}

public static void saveWallet(WalletDatabase db, File wallet_path)
throws Exception
{
wallet_path.mkdirs();

Random rnd = new Random();
byte[] rnd_data = new byte[6];
rnd.nextBytes(rnd_data);
String name = "snow-" + db.getVersion() + "_" + HexUtil.getHexString(rnd_data) + ".wallet";
File db_file = new File(wallet_path, name);
if (db_file.exists())
{
throw new RuntimeException("SOMETHING VERY UNLIKELY HAS OCCURED. ABORTING SAVE.");
}
AtomicFileOutputStream out = new AtomicFileOutputStream(db_file);

db.writeTo(out);
out.flush();
out.close();

logger.log(Level.INFO, String.format("Save to file %s completed", db_file.getPath()));
}
}
13 changes: 10 additions & 3 deletions protolib/snowblossom.proto
Expand Up @@ -284,20 +284,26 @@ message PeerList {
repeated PeerInfo peers = 1;
}


// If anything is added or changed here, it is vital to update
// WalletUtil.mergeDatabase as needed. Or else the new fields
// will not be copied in a merge resulting in terrible data loss.
message WalletDatabase {
repeated WalletKeyPair keys = 1;
repeated AddressSpec addresses = 2;
repeated Transaction transactions = 3;
int32 version = 4;
CipherKey cipher_key = 5;
map<string, bool> used_addresses = 4;
map<string, int64> address_create_time = 5;
int32 version = 10;
//CipherKey cipher_key = 11;
}

message WalletKeyPair
{
int32 signature_type = 1;
bytes public_key = 2;
bytes private_key = 3;
EncryptedPrivateKey encrypted_private_key = 4;
//EncryptedPrivateKey encrypted_private_key = 4;
}

message EncryptedPrivateKey
Expand All @@ -315,3 +321,4 @@ message CipherKey
bytes public_key = 4;

}

0 comments on commit 6eb6aa0

Please sign in to comment.