added missing obfuscations
Source Link
user1543
user1543

The Role of P_MILESTONE TO SELECT and the TransactionRequester

The actual actions of the transaction to request are further obfuscated by the last minute code block before transmission in Node.

See https://github.com/iotaledger/iri/blob/dev/src/main/java/com/iota/iri/network/Node.java#L483

synchronized (sendingPacket) {
    System.arraycopy(transactionViewModel.getBytes(), 0, sendingPacket.getData(), 0, TransactionViewModel.SIZE);
    Hash hash = transactionRequester.transactionToRequest(rnd.nextDouble() < P_SELECT_MILESTONE);
    System.arraycopy(hash != null ? hash.bytes() : transactionViewModel.getHash().bytes(), 0,
            sendingPacket.getData(), TransactionViewModel.SIZE, reqHashSize);
    neighbor.send(sendingPacket);
}

By default, P_MILESTONE_TO_SELECT is set to 70%, and this tells the transactionRequester to use a Milestone if any are found in the milestoneTransactionsToRequest queue.

See https://github.com/iotaledger/iri/blob/dev/src/main/java/com/iota/iri/network/TransactionRequester.java#L90

This further obfuscates the actions of a request, although a little investigation will find that during validation, if any trunk or branch is found to be a Milestone, then it is added to transactionsToRequest. And also, if the LedgerValidator thread also finds any missing Milestones, they too are added to the transactionsToRequest queue.

This complicates the logic of a requested transaction quite a bit as it turns out that a requested transaction of either (1) an identical hash or (2) NULL_HASH, has the effect of not //requesting a random tip as the comments in Node imply, but of an elaborate process of preferring a Milestone if one is missing from the system.

From what I can tell of the effect of the LedgerValidator, all tips are checked during the routine Milestone.java checking thread Solid Milestone Tracker and when the LedgerValidator is called, missing Milestones are inventoried and queued to receive priority treatment within the system.

I suppose this begs the question ...

How often is a Milestone missing from the system? That determines, ultimately, what a requested transaction actually requests.


The Role of P_MILESTONE TO SELECT and the TransactionRequester

The actual actions of the transaction to request are further obfuscated by the last minute code block before transmission in Node.

See https://github.com/iotaledger/iri/blob/dev/src/main/java/com/iota/iri/network/Node.java#L483

synchronized (sendingPacket) {
    System.arraycopy(transactionViewModel.getBytes(), 0, sendingPacket.getData(), 0, TransactionViewModel.SIZE);
    Hash hash = transactionRequester.transactionToRequest(rnd.nextDouble() < P_SELECT_MILESTONE);
    System.arraycopy(hash != null ? hash.bytes() : transactionViewModel.getHash().bytes(), 0,
            sendingPacket.getData(), TransactionViewModel.SIZE, reqHashSize);
    neighbor.send(sendingPacket);
}

By default, P_MILESTONE_TO_SELECT is set to 70%, and this tells the transactionRequester to use a Milestone if any are found in the milestoneTransactionsToRequest queue.

See https://github.com/iotaledger/iri/blob/dev/src/main/java/com/iota/iri/network/TransactionRequester.java#L90

This further obfuscates the actions of a request, although a little investigation will find that during validation, if any trunk or branch is found to be a Milestone, then it is added to transactionsToRequest. And also, if the LedgerValidator thread also finds any missing Milestones, they too are added to the transactionsToRequest queue.

This complicates the logic of a requested transaction quite a bit as it turns out that a requested transaction of either (1) an identical hash or (2) NULL_HASH, has the effect of not //requesting a random tip as the comments in Node imply, but of an elaborate process of preferring a Milestone if one is missing from the system.

From what I can tell of the effect of the LedgerValidator, all tips are checked during the routine Milestone.java checking thread Solid Milestone Tracker and when the LedgerValidator is called, missing Milestones are inventoried and queued to receive priority treatment within the system.

I suppose this begs the question ...

How often is a Milestone missing from the system? That determines, ultimately, what a requested transaction actually requests.

concision
Source Link
user1543
user1543
if (Arrays.equals(requestedTransaction, receivedTransaction.hash)) {
 
    if (Configuration.booling(DefaultConfSettings.EXPERIMENTAL) &&
        ++randomTipBroadcastCounter % 3 == 0) {
        log.info("Experimental: Random Tip Broadcaster.");

        final String [] tips = StorageTransactions.instance().tips().stream()
        // see code re .map(Hash:"Experimental:toString)
            .toArray(size -> new String[size]);
        final String rndTipHash = tips[rnd.nextInt(tips.length)];

        transactionPointer = StorageTransactions.instance()
          Random Tip .transactionPointer(rndTipHash.getBytes());Broadcaster"
    } else {
        transactionPointer = StorageTransactions.instance()
            .transactionPointer(Milestone.latestMilestone.bytes());
    }
} else {
    transactionPointer = StorageTransactions.instance().transactionPointer(requestedTransaction);
}
if (Arrays.equals(requestedTransaction, receivedTransaction.hash)) {
 
    if (Configuration.booling(DefaultConfSettings.EXPERIMENTAL) &&
        ++randomTipBroadcastCounter % 3 == 0) {
        log.info("Experimental: Random Tip Broadcaster.");

        final String [] tips = StorageTransactions.instance().tips().stream()
            .map(Hash::toString)
            .toArray(size -> new String[size]);
        final String rndTipHash = tips[rnd.nextInt(tips.length)];

        transactionPointer = StorageTransactions.instance()
            .transactionPointer(rndTipHash.getBytes());
    } else {
        transactionPointer = StorageTransactions.instance()
            .transactionPointer(Milestone.latestMilestone.bytes());
    }
} else {
    transactionPointer = StorageTransactions.instance().transactionPointer(requestedTransaction);
}
if (Arrays.equals(requestedTransaction, receivedTransaction.hash)) {
    if (Configuration.booling(DefaultConfSettings.EXPERIMENTAL) &&
        ++randomTipBroadcastCounter % 3 == 0) {
        // see code re "Experimental: Random Tip Broadcaster"
    } else {
        transactionPointer = StorageTransactions.instance()
            .transactionPointer(Milestone.latestMilestone.bytes());
    }
} else {
    transactionPointer = StorageTransactions.instance().transactionPointer(requestedTransaction);
}
added 129 characters in body
Source Link
user1543
user1543

After the first submitted answer below, and after Come_From_Beyond made some comments, I did some digging to see the commit history of this code. 

According to the earliest available commits for the Node class, when the transaction hash and the requested hash were the same, the request was to be the Milestone that is requested. Perhaps someone can shed some light on why this existed like this and why it was changed.

I did some digging. According to the earliest available commits for the Node class, when the transaction hash and the requested hash were the same, the request was to be the Milestone that is requested. Perhaps someone can shed some light on why this existed like this and why it was changed.

After the first submitted answer below, and after Come_From_Beyond made some comments, I did some digging to see the commit history of this code. 

According to the earliest available commits for the Node class, when the transaction hash and the requested hash were the same, the request was to be the Milestone that is requested. Perhaps someone can shed some light on why this existed like this and why it was changed.

added history
Source Link
user1543
user1543
Loading
added history
Source Link
user1543
user1543
Loading
added history of code segment in question
Source Link
user1543
user1543
Loading
edited title
Link
user1543
user1543
Loading
added 34 characters in body
Source Link
user1543
user1543
Loading
Source Link
user1543
user1543
Loading