public byte[] getBlockHashByNumber(long blockNumber) { Block chainBlock = getChainBlockByNumber(blockNumber); return chainBlock == null ? null : chainBlock .getHash(); // FIXME: can be improved by accessing the hash directly in the index }
/** * For each block we are looking for our transactions and clearing them The actual receiver * balance is confirmed upon block arrival */ public void onBlock(Block block, List<TransactionReceipt> receipts) { int cleared = 0; for (Transaction tx : block.getTransactionsList()) { ByteArrayWrapper txHash = new ByteArrayWrapper(tx.getHash()); Transaction ptx = pendingTxs.get(txHash); if (ptx != null) { logger.info( " - Pending transaction cleared 0x" + Hex.toHexString(tx.getHash()).substring(0, 8) + " in block " + block.getShortDescr()); pendingTxs.remove(txHash); cleared++; } } BigInteger receiverBalance = ethereum.getRepository().getBalance(receiverAddress); BigInteger receiverBalancePending = pendingState.getRepository().getBalance(receiverAddress); logger.info("" + cleared + " transactions cleared in the block " + block.getShortDescr()); logger.info( "Receiver pending/current balance: " + receiverBalancePending + " / " + receiverBalance + " (" + pendingTxs.size() + " pending txs)"); }
@Override public List<BlockHeader> getListHeadersEndWith(byte[] hash, long qty) { List<Block> blocks = getListBlocksEndWith(hash, qty); List<BlockHeader> headers = new ArrayList<>(blocks.size()); for (Block b : blocks) { headers.add(b.getHeader()); } return headers; }
@Override public List<byte[]> getListHashesEndWith(byte[] hash, long number) { List<Block> blocks = getListBlocksEndWith(hash, number); List<byte[]> hashes = new ArrayList<>(blocks.size()); for (Block b : blocks) { hashes.add(b.getHash()); } return hashes; }
@Override public BigInteger getTotalDifficultyForHash(byte[] hash) { Block block = this.getBlockByHash(hash); if (block == null) return ZERO; Long level = block.getNumber(); List<BlockInfo> blockInfos = index.get(level.intValue()); for (BlockInfo blockInfo : blockInfos) if (areEqual(blockInfo.getHash(), hash)) { return blockInfo.cummDifficulty; } return ZERO; }
private List<Block> getListBlocksEndWithInner(byte[] hash, long qty) { Block block = this.blocks.get(hash); if (block == null) return new ArrayList<>(); List<Block> blocks = new ArrayList<>((int) qty); for (int i = 0; i < qty; ++i) { blocks.add(block); block = this.blocks.get(block.getParentHash()); if (block == null) break; } return blocks; }
@Override public Block createForkBlock(Block parent) { try { List<Transaction> txes = new ArrayList<>(); Map<ByteArrayWrapper, Long> nonces = new HashMap<>(); Repository repoSnapshot = getBlockchain().getRepository().getSnapshotTo(parent.getStateRoot()); for (PendingTx tx : submittedTxes) { ByteArrayWrapper senderW = new ByteArrayWrapper(tx.sender.getAddress()); Long nonce = nonces.get(senderW); if (nonce == null) { BigInteger bcNonce = repoSnapshot.getNonce(tx.sender.getAddress()); nonce = bcNonce.longValue(); } nonces.put(senderW, nonce + 1); byte[] toAddress = tx.targetContract != null ? tx.targetContract.getAddress() : tx.toAddress; Transaction transaction = new Transaction( ByteUtil.longToBytesNoLeadZeroes(nonce), ByteUtil.longToBytesNoLeadZeroes(gasPrice), ByteUtil.longToBytesNoLeadZeroes(gasLimit), toAddress, ByteUtil.bigIntegerToBytes(tx.value), tx.data); transaction.sign(tx.sender.getPrivKeyBytes()); if (tx.createdContract != null) { tx.createdContract.setAddress(transaction.getContractAddress()); } txes.add(transaction); } Block b = getBlockchain().createNewBlock(parent, txes, Collections.EMPTY_LIST); Ethash.getForBlock(b.getNumber()).mineLight(b).get(); ImportResult importResult = getBlockchain().tryToConnect(b); if (importResult != ImportResult.IMPORTED_BEST && importResult != ImportResult.IMPORTED_NOT_BEST) { throw new RuntimeException( "Invalid block import result " + importResult + " for block " + b); } submittedTxes.clear(); return b; } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } }
private void addInternalBlock(Block block, BigInteger cummDifficulty, boolean mainChain) { List<BlockInfo> blockInfos = block.getNumber() >= index.size() ? new ArrayList<BlockInfo>() : index.get((int) block.getNumber()); BlockInfo blockInfo = new BlockInfo(); blockInfo.setCummDifficulty(cummDifficulty); blockInfo.setHash(block.getHash()); blockInfo.setMainChain( mainChain); // FIXME:maybe here I should force reset main chain for all uncles on that level blockInfos.add(blockInfo); index.set((int) block.getNumber(), blockInfos); blocks.put(block.getHash(), block); }
@Override public Object[] callConstFunction(Block callBlock, String functionName, Object... args) { Transaction tx = CallTransaction.createCallTransaction( 0, 0, 100000000000000L, Hex.toHexString(getAddress()), 0, contract.getByName(functionName), args); tx.sign(new byte[32]); Repository repository = getBlockchain().getRepository().getSnapshotTo(callBlock.getStateRoot()).startTracking(); try { org.ethereum.core.TransactionExecutor executor = new org.ethereum.core.TransactionExecutor( tx, callBlock.getCoinbase(), repository, getBlockchain().getBlockStore(), getBlockchain().getProgramInvokeFactory(), callBlock) .setLocalCall(true); executor.init(); executor.execute(); executor.go(); executor.finalization(); return contract.getByName(functionName).decodeResult(executor.getResult().getHReturn()); } finally { repository.rollback(); } }
@Override public void reBranch(Block forkBlock) { Block bestBlock = getBestBlock(); long maxLevel = Math.max(bestBlock.getNumber(), forkBlock.getNumber()); // 1. First ensure that you are one the save level long currentLevel = maxLevel; Block forkLine = forkBlock; if (forkBlock.getNumber() > bestBlock.getNumber()) { while (currentLevel > bestBlock.getNumber()) { List<BlockInfo> blocks = getBlockInfoForLevel(currentLevel); BlockInfo blockInfo = getBlockInfoForHash(blocks, forkLine.getHash()); if (blockInfo != null) { blockInfo.setMainChain(true); setBlockInfoForLevel(currentLevel, blocks); } forkLine = getBlockByHash(forkLine.getParentHash()); --currentLevel; } } Block bestLine = bestBlock; if (bestBlock.getNumber() > forkBlock.getNumber()) { while (currentLevel > forkBlock.getNumber()) { List<BlockInfo> blocks = getBlockInfoForLevel(currentLevel); BlockInfo blockInfo = getBlockInfoForHash(blocks, bestLine.getHash()); if (blockInfo != null) { blockInfo.setMainChain(false); setBlockInfoForLevel(currentLevel, blocks); } bestLine = getBlockByHash(bestLine.getParentHash()); --currentLevel; } } // 2. Loop back on each level until common block while (!bestLine.isEqual(forkLine)) { List<BlockInfo> levelBlocks = getBlockInfoForLevel(currentLevel); BlockInfo bestInfo = getBlockInfoForHash(levelBlocks, bestLine.getHash()); if (bestInfo != null) { bestInfo.setMainChain(false); setBlockInfoForLevel(currentLevel, levelBlocks); } BlockInfo forkInfo = getBlockInfoForHash(levelBlocks, forkLine.getHash()); if (forkInfo != null) { forkInfo.setMainChain(true); setBlockInfoForLevel(currentLevel, levelBlocks); } bestLine = getBlockByHash(bestLine.getParentHash()); forkLine = getBlockByHash(forkLine.getParentHash()); --currentLevel; } }