/** * 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 boolean equals(Object obj) { if (!(obj instanceof Transaction)) return false; Transaction tx = (Transaction) obj; return tx.hashCode() == this.hashCode(); }
@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); } }
/** * The PendingState is updated with a new pending transactions. Prints the current receiver * balance (based on blocks) and the pending balance which should immediately reflect receiver * balance change */ void onPendingTransactionReceived(Transaction tx) { logger.info("onPendingTransactionReceived: " + tx); if (Arrays.equals(tx.getSender(), senderAddress)) { BigInteger receiverBalance = ethereum.getRepository().getBalance(receiverAddress); BigInteger receiverBalancePending = pendingState.getRepository().getBalance(receiverAddress); logger.info(" + New pending transaction 0x" + Hex.toHexString(tx.getHash()).substring(0, 8)); pendingTxs.put(new ByteArrayWrapper(tx.getHash()), tx); logger.info( "Receiver pending/current balance: " + receiverBalancePending + " / " + receiverBalance + " (" + pendingTxs.size() + " pending txs)"); } }
@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(); } }
/** * Periodically send value transfer transactions and each 5 transactions wait for all sent * transactions to be included into blocks */ void sendTransactions() throws InterruptedException { // initial sender nonce needs to be retrieved from the repository // for further transactions we just do nonce++ BigInteger nonce = ethereum.getRepository().getNonce(senderAddress); int weisToSend = 100; int count = 0; while (true) { if (count < 5) { Transaction tx = new Transaction( ByteUtil.bigIntegerToBytes(nonce), ByteUtil.longToBytesNoLeadZeroes(ethereum.getGasPrice()), ByteUtil.longToBytesNoLeadZeroes(1_000_000), receiverAddress, ByteUtil.longToBytesNoLeadZeroes(weisToSend), new byte[0]); tx.sign(senderPrivateKey); logger.info("<=== Sending transaction: " + tx); ethereum.submitTransaction(tx); nonce = nonce.add(BigInteger.ONE); count++; } else { if (pendingTxs.size() > 0) { logger.info( "Waiting for transaction clearing. " + pendingTxs.size() + " transactions remain."); } else { logger.info("All transactions are included to blocks!"); count = 0; } } Thread.sleep(7000); } }
@Override public Transaction call() throws Exception { try { logger.info("call() tx: {}", tx.toString()); ClientPeer peer = MainData.instance.getActivePeer(); WalletTransaction walletTransaction = WorldManager.instance.getBlockChain().addWalletTransaction(tx); peer.sendTransaction(tx); while (walletTransaction.getApproved() < 1) { sleep(10); } logger.info("return approved: {}", walletTransaction.getApproved()); } catch (Throwable th) { logger.info("exception caugh: {}", th.getCause()); WorldManager.instance.getBlockChain().removeWalletTransaction(tx); } return null; }