@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()); }
private static void verifyDifficulty( StoredBlock prevBlock, Block added, BigInteger calcDiff, NetworkParameters params) { if (calcDiff.compareTo(params.getMaxTarget()) > 0) { log.info("Difficulty hit proof of work limit: {}", calcDiff.toString(16)); calcDiff = params.getMaxTarget(); } int accuracyBytes = (int) (added.getDifficultyTarget() >>> 24) - 3; final BigInteger receivedDifficulty = added.getDifficultyTargetAsInteger(); // The calculated difficulty is to a higher precision than received, so reduce here. final BigInteger mask = BigInteger.valueOf(0xFFFFFFL).shiftLeft(accuracyBytes * 8); calcDiff = calcDiff.and(mask); if (CoinDefinition.TEST_NETWORK_STANDARD.equals(params.getStandardNetworkId())) { if (calcDiff.compareTo(receivedDifficulty) != 0) { throw new VerificationException( "Network provided difficulty bits do not match what was calculated: " + receivedDifficulty.toString(16) + " vs " + calcDiff.toString(16)); } } else { final int height = prevBlock.getHeight() + 1; if (height <= 68589) { long nBitsNext = added.getDifficultyTarget(); long calcDiffBits = (accuracyBytes + 3) << 24; calcDiffBits |= calcDiff.shiftRight(accuracyBytes * 8).longValue(); final double n1 = CommonUtils.convertBitsToDouble(calcDiffBits); final double n2 = CommonUtils.convertBitsToDouble(nBitsNext); if (Math.abs(n1 - n2) > n1 * 0.2) { throw new VerificationException( "Network provided difficulty bits do not match what was calculated: " + receivedDifficulty.toString(16) + " vs " + calcDiff.toString(16)); } } else { if (calcDiff.compareTo(receivedDifficulty) != 0) { throw new VerificationException( "Network provided difficulty bits do not match what was calculated: " + receivedDifficulty.toString(16) + " vs " + calcDiff.toString(16)); } } } }
@Test public void coinbaseTxns() throws Exception { // Covers issue 420 where the outpoint index of a coinbase tx input was being mis-serialized. Block b = params .getGenesisBlock() .createNextBlockWithCoinbase( Block.BLOCK_VERSION_GENESIS, myKey.getPubKey(), FIFTY_COINS, Block.BLOCK_HEIGHT_GENESIS); Transaction coinbase = b.getTransactions().get(0); assertTrue(coinbase.isCoinBase()); BlockChain chain = new BlockChain(params, myWallet, new MemoryBlockStore(params)); assertTrue(chain.add(b)); // Wallet now has a coinbase tx in it. assertEquals(1, myWallet.getTransactions(true).size()); assertTrue(myWallet.getTransaction(coinbase.getHash()).isCoinBase()); Wallet wallet2 = roundTrip(myWallet); assertEquals(1, wallet2.getTransactions(true).size()); assertTrue(wallet2.getTransaction(coinbase.getHash()).isCoinBase()); }
@Override public void onBlocksDownloaded( Peer peer, Block block, FilteredBlock filteredBlock, int blocksLeft) { super.onBlocksDownloaded(peer, block, filteredBlock, blocksLeft); // Log.i(TAG, "onBlocksDownloaded"); size += block.getMessageSize(); double pct = 100.0 - (100.0 * (blocksLeft / (double) originalBlocksLeft)); if ((int) pct != lastPercent) { lastPercent = (int) pct; walletObservable.setPercSync(lastPercent); walletObservable.notifyObservers(); } }
@Override public void verifyBlockAddition( Block added, @Nullable List<Sha256Hash> filteredTxHashList, @Nullable Map<Sha256Hash, Transaction> filteredTxn) { if (network.permitsMasternodesLogic() && network.getSporkManager().isSporkActive(SporkManager.SPORK_3_INSTANTX_BLOCK_FILTERING)) { if (filteredTxHashList != null && filteredTxn != null) { List<Transaction> toCheck = Lists.newArrayListWithExpectedSize(filteredTxn.size()); for (final Sha256Hash txHash : filteredTxHashList) { final Transaction tx = filteredTxn.get(txHash); if (tx != null) toCheck.add(tx); } if (toCheck.size() > 0) { checkTxs(toCheck, added.getHashAsString()); } } else { final List<Transaction> transactions = added.getTransactions(); if (transactions != null) { checkTxs(transactions, added.getHashAsString()); } } } }
private static void kimotoGravityWellCheck( StoredBlock prevBlock, Block added, BlockStore store, NetworkParameters params) throws BlockStoreException { final long blocksTargetSpacing = (long) (2.5 * 60); // 2.5 minutes int timeDaySeconds = 60 * 60 * 24; long pastSecondsMin = timeDaySeconds / 40; long pastSecondsMax = timeDaySeconds * 7; long pastBlocksMin = pastSecondsMin / blocksTargetSpacing; long pastBlocksMax = pastSecondsMax / blocksTargetSpacing; StoredBlock blockReading = prevBlock; long pastBlocksMass = 0; long pastRateActualSeconds = 0; long pastRateTargetSeconds = 0; double pastRateAdjustmentRatio = 1.0f; BigInteger pastDifficultyAverage = BigInteger.valueOf(0); BigInteger pastDifficultyAveragePrev = BigInteger.valueOf(0); double eventHorizonDeviation; double eventHorizonDeviationFast; double eventHorizonDeviationSlow; if (prevBlock == null || prevBlock.getHeight() == 0 || (long) prevBlock.getHeight() < pastBlocksMin) { verifyDifficulty(prevBlock, added, params.getMaxTarget(), params); return; } final Block prevHeader = prevBlock.getHeader(); long latestBlockTime = prevHeader.getTimeSeconds(); for (int i = 1; blockReading.getHeight() > 0; i++) { if (pastBlocksMax > 0 && i > pastBlocksMax) { break; } pastBlocksMass++; if (i == 1) { pastDifficultyAverage = blockReading.getHeader().getDifficultyTargetAsInteger(); } else { pastDifficultyAverage = (blockReading .getHeader() .getDifficultyTargetAsInteger() .subtract(pastDifficultyAveragePrev)) .divide(BigInteger.valueOf(i)) .add(pastDifficultyAveragePrev); } pastDifficultyAveragePrev = pastDifficultyAverage; if (blockReading.getHeight() > 646120 && latestBlockTime < blockReading.getHeader().getTimeSeconds()) { // eliminates the ability to go back in time latestBlockTime = blockReading.getHeader().getTimeSeconds(); } pastRateActualSeconds = prevHeader.getTimeSeconds() - blockReading.getHeader().getTimeSeconds(); pastRateTargetSeconds = blocksTargetSpacing * pastBlocksMass; if (blockReading.getHeight() > 646120) { // this should slow down the upward difficulty change if (pastRateActualSeconds < 5) { pastRateActualSeconds = 5; } } else { if (pastRateActualSeconds < 0) { pastRateActualSeconds = 0; } } if (pastRateActualSeconds != 0 && pastRateTargetSeconds != 0) { pastRateAdjustmentRatio = (double) pastRateTargetSeconds / pastRateActualSeconds; } eventHorizonDeviation = 1 + 0.7084 * Math.pow((double) pastBlocksMass / 28.2d, -1.228); eventHorizonDeviationFast = eventHorizonDeviation; eventHorizonDeviationSlow = 1 / eventHorizonDeviation; if (pastBlocksMass >= pastBlocksMin) { if (pastRateAdjustmentRatio <= eventHorizonDeviationSlow || pastRateAdjustmentRatio >= eventHorizonDeviationFast) { break; } } blockReading = store.get(blockReading.getHeader().getPrevBlockHash()); if (blockReading == null) { return; } } BigInteger newDifficulty = pastDifficultyAverage; if (pastRateActualSeconds != 0 && pastRateTargetSeconds != 0) { newDifficulty = newDifficulty.multiply(BigInteger.valueOf(pastRateActualSeconds)); newDifficulty = newDifficulty.divide(BigInteger.valueOf(pastRateTargetSeconds)); } if (newDifficulty.compareTo(params.getMaxTarget()) > 0) { log.info("Difficulty hit proof of work limit: {}", newDifficulty.toString(16)); newDifficulty = params.getMaxTarget(); } verifyDifficulty(prevBlock, added, newDifficulty, params); }
@Test public void testAppearedAtChainHeightDepthAndWorkDone() throws Exception { // Test the TransactionConfidence appearedAtChainHeight, depth and workDone field are stored. BlockChain chain = new BlockChain(params, myWallet, new MemoryBlockStore(params)); final ArrayList<Transaction> txns = new ArrayList<Transaction>(2); myWallet.addEventListener( new AbstractWalletEventListener() { @Override public void onCoinsReceived( Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { txns.add(tx); } }); // Start by building two blocks on top of the genesis block. Block b1 = params.getGenesisBlock().createNextBlock(myAddress); BigInteger work1 = b1.getWork(); assertTrue(work1.signum() > 0); Block b2 = b1.createNextBlock(myAddress); BigInteger work2 = b2.getWork(); assertTrue(work2.signum() > 0); assertTrue(chain.add(b1)); assertTrue(chain.add(b2)); // We now have the following chain: // genesis -> b1 -> b2 // Check the transaction confidence levels are correct before wallet roundtrip. Threading.waitForUserCode(); assertEquals(2, txns.size()); TransactionConfidence confidence0 = txns.get(0).getConfidence(); TransactionConfidence confidence1 = txns.get(1).getConfidence(); assertEquals(1, confidence0.getAppearedAtChainHeight()); assertEquals(2, confidence1.getAppearedAtChainHeight()); assertEquals(2, confidence0.getDepthInBlocks()); assertEquals(1, confidence1.getDepthInBlocks()); // Roundtrip the wallet and check it has stored the depth and workDone. Wallet rebornWallet = roundTrip(myWallet); Set<Transaction> rebornTxns = rebornWallet.getTransactions(false); assertEquals(2, rebornTxns.size()); // The transactions are not guaranteed to be in the same order so sort them to be in chain // height order if required. Iterator<Transaction> it = rebornTxns.iterator(); Transaction txA = it.next(); Transaction txB = it.next(); Transaction rebornTx0, rebornTx1; if (txA.getConfidence().getAppearedAtChainHeight() == 1) { rebornTx0 = txA; rebornTx1 = txB; } else { rebornTx0 = txB; rebornTx1 = txA; } TransactionConfidence rebornConfidence0 = rebornTx0.getConfidence(); TransactionConfidence rebornConfidence1 = rebornTx1.getConfidence(); assertEquals(1, rebornConfidence0.getAppearedAtChainHeight()); assertEquals(2, rebornConfidence1.getAppearedAtChainHeight()); assertEquals(2, rebornConfidence0.getDepthInBlocks()); assertEquals(1, rebornConfidence1.getDepthInBlocks()); }