Skip to content

Commit 156af72

Browse files
authored
fix(vm): write TIP-2935 parent hash after witness permission check (#6800)
1 parent 0c741e3 commit 156af72

2 files changed

Lines changed: 17 additions & 11 deletions

File tree

framework/src/main/java/org/tron/core/db/Manager.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1633,7 +1633,6 @@ public BlockCapsule generateBlock(Miner miner, long blockTime, long timeout) {
16331633
session.reset();
16341634
session.setValue(revokingStore.buildSession());
16351635

1636-
HistoryBlockHashUtil.write(this, blockCapsule);
16371636
accountStateCallBack.preExecute(blockCapsule);
16381637

16391638
if (getDynamicPropertiesStore().getAllowMultiSign() == 1) {
@@ -1646,6 +1645,8 @@ public BlockCapsule generateBlock(Miner miner, long blockTime, long timeout) {
16461645
}
16471646
}
16481647

1648+
HistoryBlockHashUtil.write(this, blockCapsule);
1649+
16491650
Set<String> accountSet = new HashSet<>();
16501651
AtomicInteger shieldedTransCounts = new AtomicInteger(0);
16511652
List<TransactionCapsule> toBePacked = new ArrayList<>();

framework/src/test/java/org/tron/core/db/HistoryBlockHashIntegrationTest.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -256,14 +256,18 @@ public void deploySkipsWhenForeignContractPresent() {
256256
* SR / validator parity: the producer's {@code generateBlock} simulation
257257
* loop and the validator's {@code processBlock} apply loop must see the
258258
* same storage state when transactions hit {@code HISTORY_STORAGE_ADDRESS}.
259-
* That requires {@link HistoryBlockHashUtil#write} to run before the tx
260-
* loop on both paths. {@code processBlock} writes at line 1858; this test
261-
* pins the matching write inside {@code generateBlock}.
259+
* Both paths run {@link HistoryBlockHashUtil#write} before their tx loop:
260+
* {@code processBlock} after its {@code validBlock} guard, and
261+
* {@code generateBlock} after the witness-permission guard, so a failed
262+
* permission check never writes the parent hash.
262263
*
263-
* <p>Spy {@code accountStateCallBack.preExecute} — called between the
264-
* write and the tx loop on both paths — and snapshot the slot from inside
265-
* the revoking session. Pre-fix the slot is empty (write never ran);
266-
* post-fix it holds the parent block hash.
264+
* <p>In {@code generateBlock} {@code preExecute} runs ahead of the write
265+
* (it precedes the guard), so this spies
266+
* {@code accountStateCallBack.executeGenerateFinish} — the last callback
267+
* before {@code session.reset()} — and snapshots the slot from inside the
268+
* revoking session. With no pending transactions the tx loop is a no-op, so
269+
* reaching this callback means the write already ran: if it were dropped the
270+
* slot would be empty; instead it holds the parent block hash.
267271
*/
268272
@Test
269273
public void generateBlockWritesParentHashBeforeTxLoop() throws Exception {
@@ -286,7 +290,7 @@ public void generateBlockWritesParentHashBeforeTxLoop() throws Exception {
286290
chainBaseManager.getStorageRowStore());
287291
captured.set(st.getValue(new DataWord(expectedSlot)));
288292
return inv.callRealMethod();
289-
}).when(spy).preExecute(Mockito.any(BlockCapsule.class));
293+
}).when(spy).executeGenerateFinish();
290294
cbField.set(dbManager, spy);
291295

292296
try {
@@ -303,10 +307,11 @@ public void generateBlockWritesParentHashBeforeTxLoop() throws Exception {
303307
}
304308

305309
assertNotNull(
306-
"preExecute fired with an empty slot — write() must run before preExecute",
310+
"executeGenerateFinish fired with an empty slot — "
311+
+ "write() must run during block generation",
307312
captured.get());
308313
assertArrayEquals(
309-
"slot must hold the parent block hash before the tx loop runs",
314+
"slot must hold the parent block hash by the time generation finishes",
310315
expectedParentHash, captured.get().getData());
311316
}
312317

0 commit comments

Comments
 (0)