@Override public Void call() throws Exception { // Runs in an auto save thread. if (!savePending.getAndSet(false)) { // Some other scheduled request already beat us to it. return null; } Date lastBlockSeenTime = wallet.getLastBlockSeenTime(); log.info("Background saving wallet; last seen block is height {}, date {}, hash {}", wallet.getLastBlockSeenHeight(), lastBlockSeenTime != null ? Utils.dateTimeFormat(lastBlockSeenTime) : "unknown", wallet.getLastBlockSeenHash()); saveNowInternal(); return null; } };
@Override public Void call() throws Exception { // Runs in an auto save thread. if (!savePending.getAndSet(false)) { // Some other scheduled request already beat us to it. return null; } Date lastBlockSeenTime = wallet.getLastBlockSeenTime(); log.info("Background saving wallet; last seen block is height {}, date {}, hash {}", wallet.getLastBlockSeenHeight(), lastBlockSeenTime != null ? Utils.dateTimeFormat(lastBlockSeenTime) : "unknown", wallet.getLastBlockSeenHash()); saveNowInternal(); return null; } };
@Override public Void call() throws Exception { // Runs in an auto save thread. if (!savePending.getAndSet(false)) { // Some other scheduled request already beat us to it. return null; } Date lastBlockSeenTime = wallet.getLastBlockSeenTime(); log.info("Background saving wallet; last seen block is height {}, date {}, hash {}", wallet.getLastBlockSeenHeight(), lastBlockSeenTime != null ? Utils.dateTimeFormat(lastBlockSeenTime) : "unknown", wallet.getLastBlockSeenHash()); saveNowInternal(); return null; } };
@Override public Void call() throws Exception { // Runs in an auto save thread. if (!savePending.getAndSet(false)) { // Some other scheduled request already beat us to it. return null; } Date lastBlockSeenTime = wallet.getLastBlockSeenTime(); log.info("Background saving wallet; last seen block is height {}, date {}, hash {}", wallet.getLastBlockSeenHeight(), lastBlockSeenTime != null ? Utils.dateTimeFormat(lastBlockSeenTime) : "unknown", wallet.getLastBlockSeenHash()); saveNowInternal(); return null; } };
/** Actually write the wallet file to disk, using an atomic rename when possible. Runs on the current thread. */ public void saveNow() throws IOException { // Can be called by any thread. However the wallet is locked whilst saving, so we can have two saves in flight // but they will serialize (using different temp files). Date lastBlockSeenTime = wallet.getLastBlockSeenTime(); log.info("Saving wallet; last seen block is height {}, date {}, hash {}", wallet.getLastBlockSeenHeight(), lastBlockSeenTime != null ? Utils.dateTimeFormat(lastBlockSeenTime) : "unknown", wallet.getLastBlockSeenHash()); saveNowInternal(); }
/** Actually write the wallet file to disk, using an atomic rename when possible. Runs on the current thread. */ public void saveNow() throws IOException { // Can be called by any thread. However the wallet is locked whilst saving, so we can have two saves in flight // but they will serialize (using different temp files). Date lastBlockSeenTime = wallet.getLastBlockSeenTime(); log.info("Saving wallet; last seen block is height {}, date {}, hash {}", wallet.getLastBlockSeenHeight(), lastBlockSeenTime != null ? Utils.dateTimeFormat(lastBlockSeenTime) : "unknown", wallet.getLastBlockSeenHash()); saveNowInternal(); }
/** Actually write the wallet file to disk, using an atomic rename when possible. Runs on the current thread. */ public void saveNow() throws IOException { // Can be called by any thread. However the wallet is locked whilst saving, so we can have two saves in flight // but they will serialize (using different temp files). Date lastBlockSeenTime = wallet.getLastBlockSeenTime(); log.info("Saving wallet; last seen block is height {}, date {}, hash {}", wallet.getLastBlockSeenHeight(), lastBlockSeenTime != null ? Utils.dateTimeFormat(lastBlockSeenTime) : "unknown", wallet.getLastBlockSeenHash()); saveNowInternal(); }
/** Actually write the wallet file to disk, using an atomic rename when possible. Runs on the current thread. */ public void saveNow() throws IOException { // Can be called by any thread. However the wallet is locked whilst saving, so we can have two saves in flight // but they will serialize (using different temp files). if (executor.isShutdown()) return; Date lastBlockSeenTime = wallet.getLastBlockSeenTime(); log.info("Saving wallet; last seen block is height {}, date {}, hash {}", wallet.getLastBlockSeenHeight(), lastBlockSeenTime != null ? Utils.dateTimeFormat(lastBlockSeenTime) : "unknown", wallet.getLastBlockSeenHash()); saveNowInternal(); }
/** * Add a wallet to the BlockChain. Note that the wallet will be unaffected by any blocks received while it * was not part of this BlockChain. This method is useful if the wallet has just been created, and its keys * have never been in use, or if the wallet has been loaded along with the BlockChain. Note that adding multiple * wallets is not well tested! */ public final void addWallet(Wallet wallet) { addNewBestBlockListener(Threading.SAME_THREAD, wallet); addReorganizeListener(Threading.SAME_THREAD, wallet); addTransactionReceivedListener(Threading.SAME_THREAD, wallet); int walletHeight = wallet.getLastBlockSeenHeight(); int chainHeight = getBestChainHeight(); if (walletHeight != chainHeight) { log.warn("Wallet/chain height mismatch: {} vs {}", walletHeight, chainHeight); log.warn("Hashes: {} vs {}", wallet.getLastBlockSeenHash(), getChainHead().getHeader().getHash()); // This special case happens when the VM crashes because of a transaction received. It causes the updated // block store to persist, but not the wallet. In order to fix the issue, we roll back the block store to // the wallet height to make it look like as if the block has never been received. if (walletHeight < chainHeight && walletHeight > 0) { try { rollbackBlockStore(walletHeight); log.info("Rolled back block store to height {}.", walletHeight); } catch (BlockStoreException x) { log.warn("Rollback of block store failed, continuing with mismatched heights. This can happen due to a replay."); } } } }
/** * Add a wallet to the BlockChain. Note that the wallet will be unaffected by any blocks received while it * was not part of this BlockChain. This method is useful if the wallet has just been created, and its keys * have never been in use, or if the wallet has been loaded along with the BlockChain. Note that adding multiple * wallets is not well tested! */ public final void addWallet(Wallet wallet) { addNewBestBlockListener(Threading.SAME_THREAD, wallet); addReorganizeListener(Threading.SAME_THREAD, wallet); addTransactionReceivedListener(Threading.SAME_THREAD, wallet); int walletHeight = wallet.getLastBlockSeenHeight(); int chainHeight = getBestChainHeight(); if (walletHeight != chainHeight) { log.warn("Wallet/chain height mismatch: {} vs {}", walletHeight, chainHeight); log.warn("Hashes: {} vs {}", wallet.getLastBlockSeenHash(), getChainHead().getHeader().getHash()); // This special case happens when the VM crashes because of a transaction received. It causes the updated // block store to persist, but not the wallet. In order to fix the issue, we roll back the block store to // the wallet height to make it look like as if the block has never been received. if (walletHeight < chainHeight && walletHeight > 0) { try { rollbackBlockStore(walletHeight); log.info("Rolled back block store to height {}.", walletHeight); } catch (BlockStoreException x) { log.warn("Rollback of block store failed, continuing with mismatched heights. This can happen due to a replay."); } } } }
/** * Add a wallet to the BlockChain. Note that the wallet will be unaffected by any blocks received while it * was not part of this BlockChain. This method is useful if the wallet has just been created, and its keys * have never been in use, or if the wallet has been loaded along with the BlockChain. Note that adding multiple * wallets is not well tested! */ public final void addWallet(Wallet wallet) { addNewBestBlockListener(Threading.SAME_THREAD, wallet); addReorganizeListener(Threading.SAME_THREAD, wallet); addTransactionReceivedListener(Threading.SAME_THREAD, wallet); int walletHeight = wallet.getLastBlockSeenHeight(); int chainHeight = getBestChainHeight(); if (walletHeight != chainHeight) { log.warn("Wallet/chain height mismatch: {} vs {}", walletHeight, chainHeight); log.warn("Hashes: {} vs {}", wallet.getLastBlockSeenHash(), getChainHead().getHeader().getHash()); // This special case happens when the VM crashes because of a transaction received. It causes the updated // block store to persist, but not the wallet. In order to fix the issue, we roll back the block store to // the wallet height to make it look like as if the block has never been received. if (walletHeight < chainHeight && walletHeight > 0) { try { rollbackBlockStore(walletHeight); log.info("Rolled back block store to height {}.", walletHeight); } catch (BlockStoreException x) { log.warn("Rollback of block store failed, continuing with mismatched heights. This can happen due to a replay."); } } } }
/** * Add a wallet to the BlockChain. Note that the wallet will be unaffected by any blocks received while it * was not part of this BlockChain. This method is useful if the wallet has just been created, and its keys * have never been in use, or if the wallet has been loaded along with the BlockChain. Note that adding multiple * wallets is not well tested! */ public final void addWallet(Wallet wallet) { addNewBestBlockListener(Threading.SAME_THREAD, wallet); addReorganizeListener(Threading.SAME_THREAD, wallet); addTransactionReceivedListener(Threading.SAME_THREAD, wallet); int walletHeight = wallet.getLastBlockSeenHeight(); int chainHeight = getBestChainHeight(); if (walletHeight != chainHeight) { log.warn("Wallet/chain height mismatch: {} vs {}", walletHeight, chainHeight); log.warn("Hashes: {} vs {}", wallet.getLastBlockSeenHash(), getChainHead().getHeader().getHash()); // This special case happens when the VM crashes because of a transaction received. It causes the updated // block store to persist, but not the wallet. In order to fix the issue, we roll back the block store to // the wallet height to make it look like as if the block has never been received. if (walletHeight < chainHeight && walletHeight > 0) { try { rollbackBlockStore(walletHeight); log.info("Rolled back block store to height {}.", walletHeight); } catch (BlockStoreException x) { log.warn("Rollback of block store failed, continuing with mismatched heights. This can happen due to a replay."); } } } }
if (newBlockHash.equals(getLastBlockSeenHash())) return; lock.lock();
if (newBlockHash.equals(getLastBlockSeenHash())) return; lock.lock();
if (newBlockHash.equals(getLastBlockSeenHash())) return; lock.lock();
if (newBlockHash.equals(getLastBlockSeenHash())) return; lock.lock();
Sha256Hash lastSeenBlockHash = wallet.getLastBlockSeenHash(); if (lastSeenBlockHash != null) { walletBuilder.setLastSeenBlockHash(hashToByteString(lastSeenBlockHash));
Sha256Hash lastSeenBlockHash = wallet.getLastBlockSeenHash(); if (lastSeenBlockHash != null) { walletBuilder.setLastSeenBlockHash(hashToByteString(lastSeenBlockHash));
@Test public void lastBlockSeen() throws Exception { Coin v1 = valueOf(5, 0); Coin v2 = valueOf(0, 50); Coin v3 = valueOf(0, 25); Transaction t1 = createFakeTx(PARAMS, v1, myAddress); Transaction t2 = createFakeTx(PARAMS, v2, myAddress); Transaction t3 = createFakeTx(PARAMS, v3, myAddress); Block genesis = blockStore.getChainHead().getHeader(); Block b10 = makeSolvedTestBlock(genesis, t1); Block b11 = makeSolvedTestBlock(genesis, t2); Block b2 = makeSolvedTestBlock(b10, t3); Block b3 = makeSolvedTestBlock(b2); // Receive a block on the best chain - this should set the last block seen hash. chain.add(b10); assertEquals(b10.getHash(), wallet.getLastBlockSeenHash()); assertEquals(b10.getTimeSeconds(), wallet.getLastBlockSeenTimeSecs()); assertEquals(1, wallet.getLastBlockSeenHeight()); // Receive a block on the side chain - this should not change the last block seen hash. chain.add(b11); assertEquals(b10.getHash(), wallet.getLastBlockSeenHash()); // Receive block 2 on the best chain - this should change the last block seen hash. chain.add(b2); assertEquals(b2.getHash(), wallet.getLastBlockSeenHash()); // Receive block 3 on the best chain - this should change the last block seen hash despite having no txns. chain.add(b3); assertEquals(b3.getHash(), wallet.getLastBlockSeenHash()); }
@Test public void testLastBlockSeenHash() throws Exception { // Test the lastBlockSeenHash field works. // LastBlockSeenHash should be empty if never set. Wallet wallet = new Wallet(PARAMS); Protos.Wallet walletProto = new WalletProtobufSerializer().walletToProto(wallet); ByteString lastSeenBlockHash = walletProto.getLastSeenBlockHash(); assertTrue(lastSeenBlockHash.isEmpty()); // Create a block. Block block = PARAMS.getDefaultSerializer().makeBlock(BlockTest.blockBytes); Sha256Hash blockHash = block.getHash(); wallet.setLastBlockSeenHash(blockHash); wallet.setLastBlockSeenHeight(1); // Roundtrip the wallet and check it has stored the blockHash. Wallet wallet1 = roundTrip(wallet); assertEquals(blockHash, wallet1.getLastBlockSeenHash()); assertEquals(1, wallet1.getLastBlockSeenHeight()); // Test the Satoshi genesis block (hash of all zeroes) is roundtripped ok. Block genesisBlock = MainNetParams.get().getGenesisBlock(); wallet.setLastBlockSeenHash(genesisBlock.getHash()); Wallet wallet2 = roundTrip(wallet); assertEquals(genesisBlock.getHash(), wallet2.getLastBlockSeenHash()); }