/** Copy the block without transactions into the provided empty block. */ protected final void copyBitcoinHeaderTo(final Block block) { block.nonce = nonce; block.prevBlockHash = prevBlockHash; block.merkleRoot = getMerkleRoot(); block.version = version; block.time = time; block.difficultyTarget = difficultyTarget; block.transactions = null; block.hash = getHash(); }
/** * Extract from Litecoin source code, definition of regtest params. * https://github.com/litecoin-project/litecoin/blob/edc66b374ea68107c721062152dd95e6aa037d53/src/chainparams.cpp */ @Override public Block getGenesisBlock() { synchronized (LitecoinRegTestParams.class) { if (genesis == null) { genesis = super.getGenesisBlock(); genesis.setNonce(0); genesis.setDifficultyTarget(0x207fffffL); genesis.setTime(1296688602L); checkState(genesis.getVersion() == 1); checkState(genesis.getMerkleRoot().toString().equals("97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9")); checkState(genesis.getHashAsString().toLowerCase().equals("530827f38f93b43ed12af0b3ad25a288dc02ed74d6d7857862df51fc56c416f9")); genesis.verifyHeader(); } return genesis; } }
@VisibleForTesting public Block createNextBlock(@Nullable Address to, Coin value) { return createNextBlock(to, BLOCK_VERSION_GENESIS, null, getTimeSeconds() + 5, pubkeyForTesting, value, BLOCK_HEIGHT_UNKNOWN); }
@Override public Block getGenesisBlock() { synchronized (RegTestParams.class) { if (genesis == null) { genesis = super.getGenesisBlock(); genesis.setNonce(2); genesis.setDifficultyTarget(0x207fFFFFL); genesis.setTime(1296688602L); //checkState(genesis.getHashAsString().toLowerCase().equals("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); } return genesis; } }
private void checkTestnetDifficulty(StoredBlock storedPrev, Block prev, Block next) throws VerificationException, BlockStoreException { checkState(lock.isHeldByCurrentThread()); // After 15th February 2012 the rules on the testnet change to avoid people running up the difficulty // and then leaving, making it too hard to mine a block. On non-difficulty transition points, easy // blocks are allowed if there has been a span of 20 minutes without one. final long timeDelta = next.getTimeSeconds() - prev.getTimeSeconds(); // There is an integer underflow bug in bitcoin-qt that means mindiff blocks are accepted when time // goes backwards. if (timeDelta >= 0 && timeDelta > NetworkParameters.TARGET_SPACING * 2) { if (next.getDifficultyTargetAsInteger().equals(params.getMaxTarget())) return; else throw new VerificationException("Unexpected change in difficulty"); } else { // Walk backwards until we find a block that doesn't have the easiest proof of work, then check // that difficulty is equal to that one. StoredBlock cursor = storedPrev; while (!cursor.getHeader().equals(params.getGenesisBlock()) && cursor.getHeight() % params.getInterval() != 0 && cursor.getHeader().getDifficultyTargetAsInteger().equals(params.getMaxTarget())) cursor = cursor.getPrev(blockStore); BigInteger cursorTarget = cursor.getHeader().getDifficultyTargetAsInteger(); BigInteger newTarget = next.getDifficultyTargetAsInteger(); if (!cursorTarget.equals(newTarget)) throw new VerificationException("Testnet block transition that is not allowed: " + Long.toHexString(cursor.getHeader().getDifficultyTarget()) + " vs " + Long.toHexString(next.getDifficultyTarget())); } }
/** * Returns a multi-line string containing a description of the contents of * the block. Use for debugging purposes only. */ @Override public String toString() { StringBuilder s = new StringBuilder(); s.append(" block: \n"); s.append(" hash: ").append(getHashAsString()).append('\n'); s.append(" version: ").append(version); String bips = Joiner.on(", ").skipNulls().join(isBIP34() ? "BIP34" : null, isBIP66() ? "BIP66" : null, isBIP65() ? "BIP65" : null); if (!bips.isEmpty()) s.append(" (").append(bips).append(')'); s.append('\n'); s.append(" previous block: ").append(getPrevBlockHash()).append("\n"); s.append(" merkle root: ").append(getMerkleRoot()).append("\n"); s.append(" time: ").append(time).append(" (").append(Utils.dateTimeFormat(time * 1000)).append(")\n"); s.append(" difficulty target (nBits): ").append(difficultyTarget).append("\n"); s.append(" nonce: ").append(nonce).append("\n"); if (transactions != null && transactions.size() > 0) { s.append(" with ").append(transactions.size()).append(" transaction(s):\n"); for (Transaction tx : transactions) { s.append(tx); } } return s.toString(); }
@Override public Block getGenesisBlock() { synchronized (RegTestParams.class) { if (genesis == null) { genesis = super.getGenesisBlock(); genesis.setNonce(2); genesis.setDifficultyTarget(0x207fFFFFL); genesis.setTime(1296688602L); checkState(genesis.getHashAsString().toLowerCase().equals("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); } return genesis; } }
private static Block getBlock2() throws Exception { Block b2 = new Block(testNet, Block.BLOCK_VERSION_GENESIS); b2.setMerkleRoot(Sha256Hash.wrap("addc858a17e21e68350f968ccd384d6439b64aafa6c193c8b9dd66320470838b")); b2.setNonce(2642058077L); b2.setTime(1296734343L); b2.setPrevBlockHash(Sha256Hash.wrap("000000033cc282bc1fa9dcae7a533263fd7fe66490f550d80076433340831604")); assertEquals("000000037b21cac5d30fc6fda2581cf7b2612908aed2abbcc429c45b0557a15f", b2.getHashAsString()); b2.verifyHeader(); return b2; }
public UnitTestParams() { super(); id = ID_UNITTESTNET; packetMagic = 0x0b110907; addressHeader = 111; p2shHeader = 196; acceptableAddressCodes = new int[] { addressHeader, p2shHeader }; maxTarget = new BigInteger("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16); genesisBlock.setTime(System.currentTimeMillis() / 1000); genesisBlock.setDifficultyTarget(Block.EASIEST_DIFFICULTY_TARGET); genesisBlock.solve(); port = 18333; interval = 10; dumpedPrivateKeyHeader = 239; targetTimespan = 200000000; // 6 years. Just a very big number. spendableCoinbaseDepth = 5; subsidyDecreaseBlockCount = 100; dnsSeeds = null; addrSeeds = null; bip32HeaderPub = 0x043587CF; bip32HeaderPriv = 0x04358394; majorityEnforceBlockUpgrade = 3; majorityRejectBlockOutdated = 4; majorityWindow = 7; }
@Override public void notifyNewBestBlock(StoredBlock block) throws VerificationException { int height = block.getHeight(); if (height % CoinDefinition.getIntervalCheckpoints() == 0 && block.getHeader().getTimeSeconds() <= timeAgo) { System.out.println(String.format("Checkpointing block %s at height %d, time %s", block.getHeader().getHash(), block.getHeight(), Utils.dateTimeFormat(block.getHeader().getTime()))); checkpoints.put(height, block); } } });
/** * The flags indicating which script validation tests should be applied to * the given transaction. Enables support for alternative blockchains which enable * tests based on different criteria. * * @param block block the transaction belongs to. * @param transaction to determine flags for. * @param height height of the block, if known, null otherwise. Returned * tests should be a safe subset if block height is unknown. */ public EnumSet<Script.VerifyFlag> getTransactionVerificationFlags(final Block block, final Transaction transaction, final VersionTally tally, final Integer height) { final EnumSet<Script.VerifyFlag> verifyFlags = EnumSet.noneOf(Script.VerifyFlag.class); if (block.getTimeSeconds() >= NetworkParameters.BIP16_ENFORCE_TIME) verifyFlags.add(Script.VerifyFlag.P2SH); // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4 // blocks, when 75% of the network has upgraded: if (block.getVersion() >= Block.BLOCK_VERSION_BIP65 && tally.getCountAtOrAbove(Block.BLOCK_VERSION_BIP65) > this.getMajorityEnforceBlockUpgrade()) { verifyFlags.add(Script.VerifyFlag.CHECKLOCKTIMEVERIFY); } return verifyFlags; }
@Override public String toString() { return String.format(Locale.US, "Block %s at height %d: %s", getHeader().getHashAsString(), getHeight(), getHeader().toString()); } }
/** Gets the hash of the block represented in this Filtered Block */ @Override public Sha256Hash getHash() { return header.getHash(); }
final long timeDelta = nextBlock.getTimeSeconds() - prev.getTimeSeconds(); if (timeDelta >= 0 && timeDelta > NetworkParameters.TARGET_SPACING * 2) { if (!maxTarget.equals(nextBlock.getDifficultyTargetAsInteger())) throw new VerificationException("Testnet block transition that is not allowed: " + Long.toHexString(Utils.encodeCompactBits(maxTarget)) + " (required min difficulty) vs " + Long.toHexString(nextBlock.getDifficultyTarget())); return;
/** * Returns the time at which the block was solved and broadcast, according to the clock of the solving node. */ public Date getTime() { return new Date(getTimeSeconds()*1000); }
@Override public synchronized void onBlocksDownloaded(Peer peer, Block block, @Nullable FilteredBlock filteredBlock, int blocksLeft) { blocksInLastSecond++; bytesInLastSecond += Block.HEADER_SIZE; List<Transaction> blockTransactions = block.getTransactions(); // This whole area of the type hierarchy is a mess. int txCount = (blockTransactions != null ? countAndMeasureSize(blockTransactions) : 0) + (filteredBlock != null ? countAndMeasureSize(filteredBlock.getAssociatedTransactions().values()) : 0); txnsInLastSecond = txnsInLastSecond + txCount; if (filteredBlock != null) origTxnsInLastSecond += filteredBlock.getTransactionCount(); }
/** * Calculate the difficulty target expected for the next block after a normal * recalculation interval. Does not handle special cases such as testnet blocks * being setting the target to maximum for blocks after a long interval. * * @param previousHeight height of the block immediately before the retarget. * @param prev the block immediately before the retarget block. * @param nextBlock the block the retarget happens at. * @param blockIntervalAgo The last retarget block. * @return New difficulty target as compact bytes. */ protected long calculateNewDifficultyTargetInner(int previousHeight, final Block prev, final Block nextBlock, final Block blockIntervalAgo) { return this.calculateNewDifficultyTargetInner(previousHeight, prev.getTimeSeconds(), prev.getDifficultyTarget(), blockIntervalAgo.getTimeSeconds(), nextBlock.getDifficultyTarget()); }
@Override public void notifyNewBestBlock(StoredBlock block) throws VerificationException { int height = block.getHeight(); if (height % PARAMS.getInterval() == 0 && block.getHeader().getTimeSeconds() <= oneMonthAgo) { System.out.println(String.format("Checkpointing block %s at height %d", block.getHeader().getHash(), block.getHeight())); checkpoints.put(height, block); } } }, Threading.SAME_THREAD);
/** * An orphan block is one that does not connect to the chain anywhere (ie we can't find its parent, therefore * it's an orphan). Typically this occurs when we are downloading the chain and didn't reach the head yet, and/or * if a block is solved whilst we are downloading. It's possible that we see a small amount of orphan blocks which * chain together, this method tries walking backwards through the known orphan blocks to find the bottom-most. * * @return from or one of froms parents, or null if "from" does not identify an orphan block */ @Nullable public Block getOrphanRoot(Sha256Hash from) { lock.lock(); try { OrphanBlock cursor = orphanBlocks.get(from); if (cursor == null) return null; OrphanBlock tmp; while ((tmp = orphanBlocks.get(cursor.block.getPrevBlockHash())) != null) { cursor = tmp; } return cursor.block; } finally { lock.unlock(); } }
/** * Gets a list of leaf hashes which are contained in the partial merkle tree in this filtered block * * @throws ProtocolException If the partial merkle block is invalid or the merkle root of the partial merkle block doesnt match the block header */ public List<Sha256Hash> getTransactionHashes() throws VerificationException { if (cachedTransactionHashes != null) return Collections.unmodifiableList(cachedTransactionHashes); List<Sha256Hash> hashesMatched = new LinkedList<Sha256Hash>(); if (header.getMerkleRoot().equals(merkleTree.getTxnHashAndMerkleRoot(hashesMatched))) { cachedTransactionHashes = hashesMatched; return Collections.unmodifiableList(cachedTransactionHashes); } else throw new VerificationException("Merkle root of block header does not match merkle root of partial merkle tree."); }