Update 2023/3/30
public void notify(final TransactionHashesNotification notification, final BlockNotificationContext context) { if (NotificationTrigger.Execute == context.getTrigger()) { this.transactionHashCache.putAll(notification.getPairs()); } ...
TransactionsHashesNotification
が作成された時、 streamDefault
が使用され、 内部及び外部トランザクションに拡張されたことです:protected void notifyTransactionHashes() { final List<HashMetaDataPair> pairs = BlockExtensions.streamDefault(this.block) .map(t -> new HashMetaDataPair(HashUtils.calculateHash(t), new HashMetaData(this.block.getHeight(), t.getTimeStamp()))) .collect(Collectors.toList()); this.observer.notify(new TransactionHashesNotification(pairs)); }
BatchUniqueHashTransactionValidator
は、H(MT')がHashTransactionsCacheにないことをチェックするので、それはUnconfirmedTransactionsCacheに追加されます ✅public ValidationResult validate(final List<TransactionsContextPair> groupedTransactions) { ... final List<Hash> hashes = groupedTransactions.stream().flatMap(pair -> pair.getTransactions().stream()) .map(HashUtils::calculateHash).collect(Collectors.toList()); return this.validate(hashes); }
pair.getTransactions()
が 外部トランザクションしか含まれていない Collection<Transaction>
を返すことです。 結果として、 H(MT') != H(MT) はチェックされますが、 H(X) はチェックされません。BlockUniqueHashTransactionValidator
は、BatchUniqueHashTransactionValidator
と同じロジックを持つため、外部トランザクション MT'のハッシュのみがチェックされます。 その結果、トランザクションはハーベストされたブロックに含まれます。 ✅public ValidationResult validate(final Block ... final List<Hash> hashes = block.getTransactions().stream().map(HashUtils::calculateHash).collect(Collectors.toList()); return this.transactionHashCache.anyHashExists(hashes) ? ValidationResult.NEUTRAL : ValidationResult.SUCCESS; }
TransactionHashesObserver
は、状態の変更を行うブロック処理の一部で、H(MT') H(X)の両方をHashTransactionsCache
に登録しようとします。ですが既に H(X) は UnconfirmedTransactionsCache
に存在するために失敗し、ハーベストされたブロックは拒否されます。 🛑UnconfirmedTransactionsCache
ステップ5へ進みます。TransactionExtensions.streamDefault()
を用いることで解決されます。TransactionExtensions.streamDefault
を追加することで、MT' (または類似のもの) が `UnconfirmedTransactionsCache への追加を防ぐことができます。public ValidationResult validate(final List<TransactionsContextPair> groupedTransactions) { if (groupedTransactions.isEmpty()) { return ValidationResult.SUCCESS; } final List<Hash> hashes = groupedTransactions.stream().flatMap(pair -> pair.getTransactions().stream()) .flatMap(transaction -> TransactionExtensions.streamDefault(transaction)).map(HashUtils::calculateHash) .collect(Collectors.toList()); return this.validate(hashes); }
TransactionExtensions.streamDefault
を追加することで、MT' (または類似のもの) が新たにハーベストされるブロックへの追加を防ぐことができます。public ValidationResult validate(final Block block) { if (block.getTransactions().isEmpty()) { return ValidationResult.SUCCESS; } final List<Hash> hashes = block.getTransactions().stream().flatMap(transaction -> TransactionExtensions.streamDefault(transaction)) .map(HashUtils::calculateHash).collect(Collectors.toList()); return this.transactionHashCache.anyHashExists(hashes) ? ValidationResult.NEUTRAL : ValidationResult.SUCCESS; }