mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-14 19:25:51 +00:00
Fix #1078. Add ability to load Wallet without loading its transactions. Use new methods with wallet-tool reset (where transactions are deleted anyway) and with wallet-tool sync (if the --force option is provided).
This commit is contained in:
parent
7c8c2a4b02
commit
66a851bd30
@ -68,7 +68,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
* You can extend the wallet format with additional fields specific to your application if you want, but make sure
|
||||
* to either put the extra data in the provided extension areas, or select tag numbers that are unlikely to be used
|
||||
* by anyone else.<p>
|
||||
*
|
||||
*
|
||||
* @author Miron Cuperman
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
@ -235,7 +235,7 @@ public class WalletProtobufSerializer {
|
||||
private static Protos.Transaction makeTxProto(WalletTransaction wtx) {
|
||||
Transaction tx = wtx.getTransaction();
|
||||
Protos.Transaction.Builder txBuilder = Protos.Transaction.newBuilder();
|
||||
|
||||
|
||||
txBuilder.setPool(getProtoPool(wtx))
|
||||
.setHash(hashToByteString(tx.getHash()))
|
||||
.setVersion((int) tx.getVersion());
|
||||
@ -243,11 +243,11 @@ public class WalletProtobufSerializer {
|
||||
if (tx.getUpdateTime() != null) {
|
||||
txBuilder.setUpdatedAt(tx.getUpdateTime().getTime());
|
||||
}
|
||||
|
||||
|
||||
if (tx.getLockTime() > 0) {
|
||||
txBuilder.setLockTime((int)tx.getLockTime());
|
||||
}
|
||||
|
||||
|
||||
// Handle inputs.
|
||||
for (TransactionInput input : tx.getInputs()) {
|
||||
Protos.TransactionInput.Builder inputBuilder = Protos.TransactionInput.newBuilder()
|
||||
@ -260,7 +260,7 @@ public class WalletProtobufSerializer {
|
||||
inputBuilder.setValue(input.getValue().value);
|
||||
txBuilder.addTransactionInput(inputBuilder);
|
||||
}
|
||||
|
||||
|
||||
// Handle outputs.
|
||||
for (TransactionOutput output : tx.getOutputs()) {
|
||||
Protos.TransactionOutput.Builder outputBuilder = Protos.TransactionOutput.newBuilder()
|
||||
@ -275,7 +275,7 @@ public class WalletProtobufSerializer {
|
||||
}
|
||||
txBuilder.addTransactionOutput(outputBuilder);
|
||||
}
|
||||
|
||||
|
||||
// Handle which blocks tx was seen in.
|
||||
final Map<Sha256Hash, Integer> appearsInHashes = tx.getAppearsInHashes();
|
||||
if (appearsInHashes != null) {
|
||||
@ -284,7 +284,7 @@ public class WalletProtobufSerializer {
|
||||
txBuilder.addBlockRelativityOffsets(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (tx.hasConfidence()) {
|
||||
TransactionConfidence confidence = tx.getConfidence();
|
||||
Protos.TransactionConfidence.Builder confidenceBuilder = Protos.TransactionConfidence.newBuilder();
|
||||
@ -315,7 +315,7 @@ public class WalletProtobufSerializer {
|
||||
|
||||
if (tx.getMemo() != null)
|
||||
txBuilder.setMemo(tx.getMemo());
|
||||
|
||||
|
||||
return txBuilder.build();
|
||||
}
|
||||
|
||||
@ -389,13 +389,33 @@ public class WalletProtobufSerializer {
|
||||
* @throws UnreadableWalletException thrown in various error conditions (see description).
|
||||
*/
|
||||
public Wallet readWallet(InputStream input, @Nullable WalletExtension... walletExtensions) throws UnreadableWalletException {
|
||||
return readWallet(input, false, walletExtensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Loads wallet data from the given protocol buffer and inserts it into the given Wallet object. This is primarily
|
||||
* useful when you wish to pre-register extension objects. Note that if loading fails the provided Wallet object
|
||||
* may be in an indeterminate state and should be thrown away. Do not simply call this method again on the same
|
||||
* Wallet object with {@code forceReset} set {@code true}. It won't work.</p>
|
||||
*
|
||||
* <p>If {@code forceReset} is {@code true}, then no transactions are loaded from the wallet, and it is configured
|
||||
* to replay transactions from the blockchain (as if the wallet had been loaded and {@link Wallet.reset}
|
||||
* had been called immediately thereafter).
|
||||
*
|
||||
* <p>A wallet can be unreadable for various reasons, such as inability to open the file, corrupt data, internally
|
||||
* inconsistent data, a wallet extension marked as mandatory that cannot be handled and so on. You should always
|
||||
* handle {@link UnreadableWalletException} and communicate failure to the user in an appropriate manner.</p>
|
||||
*
|
||||
* @throws UnreadableWalletException thrown in various error conditions (see description).
|
||||
*/
|
||||
public Wallet readWallet(InputStream input, boolean forceReset, @Nullable WalletExtension[] extensions) throws UnreadableWalletException {
|
||||
try {
|
||||
Protos.Wallet walletProto = parseToProto(input);
|
||||
final String paramsID = walletProto.getNetworkIdentifier();
|
||||
NetworkParameters params = NetworkParameters.fromID(paramsID);
|
||||
if (params == null)
|
||||
throw new UnreadableWalletException("Unknown network parameters ID " + paramsID);
|
||||
return readWallet(params, walletExtensions, walletProto);
|
||||
return readWallet(params, extensions, walletProto, forceReset);
|
||||
} catch (IOException e) {
|
||||
throw new UnreadableWalletException("Could not parse input stream to protobuf", e);
|
||||
} catch (IllegalStateException e) {
|
||||
@ -416,6 +436,27 @@ public class WalletProtobufSerializer {
|
||||
*/
|
||||
public Wallet readWallet(NetworkParameters params, @Nullable WalletExtension[] extensions,
|
||||
Protos.Wallet walletProto) throws UnreadableWalletException {
|
||||
return readWallet(params, extensions, walletProto, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Loads wallet data from the given protocol buffer and inserts it into the given Wallet object. This is primarily
|
||||
* useful when you wish to pre-register extension objects. Note that if loading fails the provided Wallet object
|
||||
* may be in an indeterminate state and should be thrown away. Do not simply call this method again on the same
|
||||
* Wallet object with {@code forceReset} set {@code true}. It won't work.</p>
|
||||
*
|
||||
* <p>If {@code forceReset} is {@code true}, then no transactions are loaded from the wallet, and it is configured
|
||||
* to replay transactions from the blockchain (as if the wallet had been loaded and {@link Wallet.reset}
|
||||
* had been called immediately thereafter).
|
||||
*
|
||||
* <p>A wallet can be unreadable for various reasons, such as inability to open the file, corrupt data, internally
|
||||
* inconsistent data, a wallet extension marked as mandatory that cannot be handled and so on. You should always
|
||||
* handle {@link UnreadableWalletException} and communicate failure to the user in an appropriate manner.</p>
|
||||
*
|
||||
* @throws UnreadableWalletException thrown in various error conditions (see description).
|
||||
*/
|
||||
public Wallet readWallet(NetworkParameters params, @Nullable WalletExtension[] extensions,
|
||||
Protos.Wallet walletProto, boolean forceReset) throws UnreadableWalletException {
|
||||
if (walletProto.getVersion() > CURRENT_WALLET_VERSION)
|
||||
throw new UnreadableWalletException.FutureVersion();
|
||||
if (!walletProto.getNetworkIdentifier().equals(params.getId()))
|
||||
@ -450,33 +491,40 @@ public class WalletProtobufSerializer {
|
||||
wallet.setDescription(walletProto.getDescription());
|
||||
}
|
||||
|
||||
// Read all transactions and insert into the txMap.
|
||||
for (Protos.Transaction txProto : walletProto.getTransactionList()) {
|
||||
readTransaction(txProto, wallet.getParams());
|
||||
}
|
||||
|
||||
// Update transaction outputs to point to inputs that spend them
|
||||
for (Protos.Transaction txProto : walletProto.getTransactionList()) {
|
||||
WalletTransaction wtx = connectTransactionOutputs(txProto);
|
||||
wallet.addWalletTransaction(wtx);
|
||||
}
|
||||
|
||||
// Update the lastBlockSeenHash.
|
||||
if (!walletProto.hasLastSeenBlockHash()) {
|
||||
if (forceReset) {
|
||||
// Should mirror Wallet.reset()
|
||||
wallet.setLastBlockSeenHash(null);
|
||||
} else {
|
||||
wallet.setLastBlockSeenHash(byteStringToHash(walletProto.getLastSeenBlockHash()));
|
||||
}
|
||||
if (!walletProto.hasLastSeenBlockHeight()) {
|
||||
wallet.setLastBlockSeenHeight(-1);
|
||||
wallet.setLastBlockSeenTimeSecs(0);
|
||||
} else {
|
||||
wallet.setLastBlockSeenHeight(walletProto.getLastSeenBlockHeight());
|
||||
}
|
||||
// Will default to zero if not present.
|
||||
wallet.setLastBlockSeenTimeSecs(walletProto.getLastSeenBlockTimeSecs());
|
||||
// Read all transactions and insert into the txMap.
|
||||
for (Protos.Transaction txProto : walletProto.getTransactionList()) {
|
||||
readTransaction(txProto, wallet.getParams());
|
||||
}
|
||||
|
||||
if (walletProto.hasKeyRotationTime()) {
|
||||
wallet.setKeyRotationTime(new Date(walletProto.getKeyRotationTime() * 1000));
|
||||
// Update transaction outputs to point to inputs that spend them
|
||||
for (Protos.Transaction txProto : walletProto.getTransactionList()) {
|
||||
WalletTransaction wtx = connectTransactionOutputs(txProto);
|
||||
wallet.addWalletTransaction(wtx);
|
||||
}
|
||||
|
||||
// Update the lastBlockSeenHash.
|
||||
if (!walletProto.hasLastSeenBlockHash()) {
|
||||
wallet.setLastBlockSeenHash(null);
|
||||
} else {
|
||||
wallet.setLastBlockSeenHash(byteStringToHash(walletProto.getLastSeenBlockHash()));
|
||||
}
|
||||
if (!walletProto.hasLastSeenBlockHeight()) {
|
||||
wallet.setLastBlockSeenHeight(-1);
|
||||
} else {
|
||||
wallet.setLastBlockSeenHeight(walletProto.getLastSeenBlockHeight());
|
||||
}
|
||||
// Will default to zero if not present.
|
||||
wallet.setLastBlockSeenTimeSecs(walletProto.getLastSeenBlockTimeSecs());
|
||||
|
||||
if (walletProto.hasKeyRotationTime()) {
|
||||
wallet.setKeyRotationTime(new Date(walletProto.getKeyRotationTime() * 1000));
|
||||
}
|
||||
}
|
||||
|
||||
loadExtensions(wallet, extensions != null ? extensions : new WalletExtension[0], walletProto);
|
||||
@ -554,7 +602,7 @@ public class WalletProtobufSerializer {
|
||||
if (txProto.hasUpdatedAt()) {
|
||||
tx.setUpdateTime(new Date(txProto.getUpdatedAt()));
|
||||
}
|
||||
|
||||
|
||||
for (Protos.TransactionOutput outputProto : txProto.getTransactionOutputList()) {
|
||||
Coin value = Coin.valueOf(outputProto.getValue());
|
||||
byte[] scriptBytes = outputProto.getScriptBytes().toByteArray();
|
||||
@ -656,7 +704,7 @@ public class WalletProtobufSerializer {
|
||||
input.connect(output);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (txProto.hasConfidence()) {
|
||||
Protos.TransactionConfidence confidenceProto = txProto.getConfidence();
|
||||
TransactionConfidence confidence = tx.getConfidence();
|
||||
@ -737,7 +785,7 @@ public class WalletProtobufSerializer {
|
||||
|
||||
/**
|
||||
* Cheap test to see if input stream is a wallet. This checks for a magic value at the beginning of the stream.
|
||||
*
|
||||
*
|
||||
* @param is
|
||||
* input stream to test
|
||||
* @return true if input stream is a wallet
|
||||
|
@ -311,11 +311,14 @@ public class WalletTool {
|
||||
|
||||
InputStream walletInputStream = null;
|
||||
try {
|
||||
boolean forceReset = action == ActionEnum.RESET
|
||||
|| (action == ActionEnum.SYNC
|
||||
&& options.has("force"));
|
||||
WalletProtobufSerializer loader = new WalletProtobufSerializer();
|
||||
if (options.has("ignore-mandatory-extensions"))
|
||||
loader.setRequireMandatoryExtensions(false);
|
||||
walletInputStream = new BufferedInputStream(new FileInputStream(walletFile));
|
||||
wallet = loader.readWallet(walletInputStream);
|
||||
wallet = loader.readWallet(walletInputStream, forceReset, (WalletExtension[])(null));
|
||||
if (!wallet.getParams().equals(params)) {
|
||||
System.err.println("Wallet does not match requested network parameters: " +
|
||||
wallet.getParams().getId() + " vs " + params.getId());
|
||||
@ -372,7 +375,7 @@ public class WalletTool {
|
||||
System.err.println("************** WALLET IS INCONSISTENT *****************");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
saveWallet(walletFile);
|
||||
|
||||
if (options.has(waitForFlag)) {
|
||||
|
@ -24,7 +24,7 @@ Usage: wallet-tool --flags action-name
|
||||
current-receive-addr Prints the current receive address, deriving one if needed. Addresses derived with this action are
|
||||
independent of addresses derived with the add-key action.
|
||||
sync Sync the wallet with the latest block chain (download new transactions).
|
||||
If the chain file does not exist this will RESET the wallet.
|
||||
If the chain file does not exist or if --force is present, this will RESET the wallet.
|
||||
reset Deletes all transactions from the wallet, for if you want to replay the chain.
|
||||
send Creates and broadcasts a transaction from the given wallet.
|
||||
Requires either --output or --payment-request to be specified.
|
||||
@ -82,4 +82,4 @@ will be printed. Waiting occurs after the --action is performed, if any is speci
|
||||
--waitfor=EVER Never quit.
|
||||
--waitfor=WALLET_TX Any transaction that sends coins to or from the wallet.
|
||||
--waitfor=BLOCK A new block that builds on the best chain.
|
||||
--waitfor=BALANCE Waits until the wallets balance meets the --condition.\n";
|
||||
--waitfor=BALANCE Waits until the wallets balance meets the --condition.\n";
|
||||
|
Loading…
x
Reference in New Issue
Block a user