-
Notifications
You must be signed in to change notification settings - Fork 1.7k
fix(net): exit solidity node block sync on shutdown #6804
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f6ccd65
9a5436a
3e4ddbb
679a98c
05baeb8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ | |
| import com.google.protobuf.Any; | ||
| import com.google.protobuf.ByteString; | ||
| import com.google.protobuf.InvalidProtocolBufferException; | ||
| import java.lang.reflect.Field; | ||
| import java.security.SignatureException; | ||
| import java.util.Arrays; | ||
| import java.util.HashSet; | ||
|
|
@@ -45,6 +46,8 @@ | |
| import org.tron.common.zksnark.LibrustzcashParam.IvkToPkdParams; | ||
| import org.tron.common.zksnark.LibrustzcashParam.OutputProofParams; | ||
| import org.tron.common.zksnark.LibrustzcashParam.SpendSigParams; | ||
| import org.tron.consensus.dpos.DposSlot; | ||
| import org.tron.consensus.dpos.DposTask; | ||
| import org.tron.core.Wallet; | ||
| import org.tron.core.actuator.Actuator; | ||
| import org.tron.core.actuator.ActuatorCreator; | ||
|
|
@@ -140,14 +143,16 @@ public class ShieldedReceiveTest extends BaseTest { | |
| @Resource | ||
| private ConsensusService consensusService; | ||
| @Resource | ||
| private DposTask dposTask; | ||
| @Resource | ||
| private Wallet wallet; | ||
| @Resource | ||
| private TransactionUtil transactionUtil; | ||
| private DposSlot dposSlot; | ||
|
|
||
| private static boolean init; | ||
|
|
||
| static { | ||
| Args.setParam(new String[]{"--output-directory", dbPath(), "-w"}, SHIELD_CONF); | ||
| Args.setParam(new String[] {"--output-directory", dbPath(), "-w"}, SHIELD_CONF); | ||
| ADDRESS_ONE_PRIVATE_KEY = getRandomPrivateKey(); | ||
| FROM_ADDRESS = getHexAddressByPrivateKey(ADDRESS_ONE_PRIVATE_KEY); | ||
| } | ||
|
|
@@ -331,7 +336,7 @@ public void testBroadcastBeforeAllowZksnark() | |
|
|
||
| //Add public address sign | ||
| transactionCap = TransactionUtils.addTransactionSign(transactionCap.getInstance(), | ||
| ADDRESS_ONE_PRIVATE_KEY, chainBaseManager.getAccountStore()); | ||
| ADDRESS_ONE_PRIVATE_KEY, chainBaseManager.getAccountStore()); | ||
| try { | ||
| dbManager.pushTransaction(transactionCap); | ||
| } catch (Exception e) { | ||
|
|
@@ -433,7 +438,7 @@ public String[] generateSpendAndOutputParams() throws ZksnarkException, BadItemE | |
| boolean ok2 = JLibrustzcash.librustzcashSaplingCheckOutput(checkOutputParams); | ||
| Assert.assertTrue(ok2); | ||
|
|
||
| return new String[]{ByteArray.toHexString(checkSpendParamsData), | ||
| return new String[] {ByteArray.toHexString(checkSpendParamsData), | ||
| ByteArray.toHexString(dataToBeSigned), | ||
| ByteArray.toHexString(checkOutputParams.encode())}; | ||
| } | ||
|
|
@@ -2402,128 +2407,158 @@ public void pushSameSkAndScanAndSpend() throws Exception { | |
| assert ecKey != null; | ||
| byte[] witnessAddress = ecKey.getAddress(); | ||
| WitnessCapsule witnessCapsule = new WitnessCapsule(ByteString.copyFrom(witnessAddress)); | ||
| chainBaseManager.addWitness(ByteString.copyFrom(witnessAddress)); | ||
|
|
||
| //sometimes generate block failed, try several times. | ||
| long time = System.currentTimeMillis(); | ||
| Block block = getSignedBlock(witnessCapsule.getAddress(), time, privateKey); | ||
| dbManager.pushBlock(new BlockCapsule(block)); | ||
|
|
||
| //create transactions | ||
| chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); | ||
| chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(1000 * 1000000L); | ||
| ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); | ||
|
|
||
| // generate spend proof | ||
| SpendingKey sk = SpendingKey | ||
| .decode("ff2c06269315333a9207f817d2eca0ac555ca8f90196976324c7756504e7c9ee"); | ||
| ExpandedSpendingKey expsk = sk.expandedSpendingKey(); | ||
| byte[] senderOvk = expsk.getOvk(); | ||
| PaymentAddress address = sk.defaultAddress(); | ||
| Note note = new Note(address, 1000 * 1000000L); | ||
| IncrementalMerkleVoucherContainer voucher = createSimpleMerkleVoucherContainer(note.cm()); | ||
| byte[] anchor = voucher.root().getContent().toByteArray(); | ||
| chainBaseManager.getMerkleContainer() | ||
| .putMerkleTreeIntoStore(anchor, voucher.getVoucherCapsule().getTree()); | ||
| builder.addSpend(expsk, note, anchor, voucher); | ||
|
|
||
| // generate output proof | ||
| SpendingKey sk2 = SpendingKey.random(); | ||
| FullViewingKey fullViewingKey = sk2.fullViewingKey(); | ||
| IncomingViewingKey incomingViewingKey = fullViewingKey.inViewingKey(); | ||
|
|
||
| byte[] memo = org.tron.keystore.Wallet.generateRandomBytes(512); | ||
|
|
||
| //send coin to 2 different address generated by same sk | ||
| DiversifierT d1 = DiversifierT.random(); | ||
| PaymentAddress paymentAddress1 = incomingViewingKey.address(d1).get(); | ||
| builder.addOutput(senderOvk, paymentAddress1, | ||
| (1000 * 1000000L - wallet.getShieldedTransactionFee()) / 2, memo); | ||
|
|
||
| DiversifierT d2 = DiversifierT.random(); | ||
| PaymentAddress paymentAddress2 = incomingViewingKey.address(d2).get(); | ||
| builder.addOutput(senderOvk, paymentAddress2, | ||
| (1000 * 1000000L - wallet.getShieldedTransactionFee()) / 2, memo); | ||
|
|
||
| TransactionCapsule transactionCap = builder.build(); | ||
| // Stop the consensus task before modifying the witness schedule: DposTask uses the same | ||
| // localwitness key and would otherwise race to produce blocks at the same slot, | ||
| // triggering fork resolution and making the test slow. | ||
| consensusService.stop(); | ||
|
317787106 marked this conversation as resolved.
|
||
| try { | ||
| chainBaseManager.addWitness(ByteString.copyFrom(witnessAddress)); | ||
|
|
||
| long time = nextScheduledTime(witnessCapsule.getAddress()); | ||
| Block block = getSignedBlock(witnessCapsule.getAddress(), time, privateKey); | ||
| dbManager.pushBlock(new BlockCapsule(block)); | ||
|
|
||
| //create transactions | ||
| chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); | ||
| chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(1000 * 1000000L); | ||
| ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); | ||
|
|
||
| // generate spend proof | ||
| SpendingKey sk = SpendingKey | ||
| .decode("ff2c06269315333a9207f817d2eca0ac555ca8f90196976324c7756504e7c9ee"); | ||
| ExpandedSpendingKey expsk = sk.expandedSpendingKey(); | ||
| byte[] senderOvk = expsk.getOvk(); | ||
| PaymentAddress address = sk.defaultAddress(); | ||
| Note note = new Note(address, 1000 * 1000000L); | ||
| IncrementalMerkleVoucherContainer voucher = createSimpleMerkleVoucherContainer(note.cm()); | ||
| byte[] anchor = voucher.root().getContent().toByteArray(); | ||
| chainBaseManager.getMerkleContainer() | ||
| .putMerkleTreeIntoStore(anchor, voucher.getVoucherCapsule().getTree()); | ||
| builder.addSpend(expsk, note, anchor, voucher); | ||
|
|
||
| // generate output proof | ||
| SpendingKey sk2 = SpendingKey.random(); | ||
| FullViewingKey fullViewingKey = sk2.fullViewingKey(); | ||
| IncomingViewingKey incomingViewingKey = fullViewingKey.inViewingKey(); | ||
|
|
||
| byte[] memo = org.tron.keystore.Wallet.generateRandomBytes(512); | ||
|
|
||
| //send coin to 2 different address generated by same sk | ||
| DiversifierT d1 = DiversifierT.random(); | ||
| PaymentAddress paymentAddress1 = incomingViewingKey.address(d1).get(); | ||
| builder.addOutput(senderOvk, paymentAddress1, | ||
| (1000 * 1000000L - wallet.getShieldedTransactionFee()) / 2, memo); | ||
|
|
||
| DiversifierT d2 = DiversifierT.random(); | ||
| PaymentAddress paymentAddress2 = incomingViewingKey.address(d2).get(); | ||
| builder.addOutput(senderOvk, paymentAddress2, | ||
| (1000 * 1000000L - wallet.getShieldedTransactionFee()) / 2, memo); | ||
|
|
||
| byte[] trxId = transactionCap.getTransactionId().getBytes(); | ||
| boolean ok = dbManager.pushTransaction(transactionCap); | ||
| Assert.assertTrue(ok); | ||
| TransactionCapsule transactionCap = builder.build(); | ||
|
|
||
| Thread.sleep(500); | ||
| //package transaction to block | ||
| block = getSignedBlock(witnessCapsule.getAddress(), time + 3000, privateKey); | ||
| dbManager.pushBlock(new BlockCapsule(block)); | ||
|
|
||
| BlockCapsule blockCapsule3 = new BlockCapsule(wallet.getNowBlock()); | ||
| Assert.assertEquals("blocknum != 2", 2, blockCapsule3.getNum()); | ||
|
|
||
| block = getSignedBlock(witnessCapsule.getAddress(), time + 6000, privateKey); | ||
| dbManager.pushBlock(new BlockCapsule(block)); | ||
|
|
||
| // scan note by ivk | ||
| byte[] receiverIvk = incomingViewingKey.getValue(); | ||
| DecryptNotes notes1 = wallet.scanNoteByIvk(0, 100, receiverIvk); | ||
| Assert.assertEquals(2, notes1.getNoteTxsCount()); | ||
|
|
||
| // scan note by ivk and mark | ||
| DecryptNotesMarked notes3 = wallet.scanAndMarkNoteByIvk(0, 100, receiverIvk, | ||
| fullViewingKey.getAk(), fullViewingKey.getNk()); | ||
| Assert.assertEquals(2, notes3.getNoteTxsCount()); | ||
|
|
||
| // scan note by ovk | ||
| DecryptNotes notes2 = wallet.scanNoteByOvk(0, 100, senderOvk); | ||
| Assert.assertEquals(2, notes2.getNoteTxsCount()); | ||
|
|
||
| // to spend received note above. | ||
| ZenTransactionBuilder builder2 = new ZenTransactionBuilder(wallet); | ||
|
|
||
| //query merkleinfo | ||
| OutputPointInfo.Builder request = OutputPointInfo.newBuilder(); | ||
| for (int i = 0; i < notes1.getNoteTxsCount(); i++) { | ||
| OutputPoint.Builder outPointBuild = OutputPoint.newBuilder(); | ||
| outPointBuild.setHash(ByteString.copyFrom(trxId)); | ||
| outPointBuild.setIndex(i); | ||
| request.addOutPoints(outPointBuild.build()); | ||
| } | ||
| request.setBlockNum(1); | ||
| IncrementalMerkleVoucherInfo merkleVoucherInfo = wallet | ||
| .getMerkleTreeVoucherInfo(request.build()); | ||
|
|
||
| //build spend proof. allow only one note in spend | ||
| ExpandedSpendingKey expsk2 = sk2.expandedSpendingKey(); | ||
| for (int i = 0; i < 1; i++) { | ||
| org.tron.api.GrpcAPI.Note grpcNote = notes1.getNoteTxs(i).getNote(); | ||
| PaymentAddress paymentAddress = KeyIo.decodePaymentAddress(grpcNote.getPaymentAddress()); | ||
| Note note2 = new Note(paymentAddress.getD(), | ||
| paymentAddress.getPkD(), | ||
| grpcNote.getValue(), | ||
| grpcNote.getRcm().toByteArray() | ||
| ); | ||
| byte[] trxId = transactionCap.getTransactionId().getBytes(); | ||
| boolean ok = dbManager.pushTransaction(transactionCap); | ||
| Assert.assertTrue(ok); | ||
|
|
||
| Thread.sleep(500); | ||
| //package transaction to block | ||
| long expectedBlockNum = chainBaseManager.getDynamicPropertiesStore() | ||
| .getLatestBlockHeaderNumber() + 1; | ||
| block = getSignedBlock(witnessCapsule.getAddress(), | ||
| nextScheduledTime(witnessCapsule.getAddress()), privateKey); | ||
| dbManager.pushBlock(new BlockCapsule(block)); | ||
|
|
||
| BlockCapsule blockCapsule3 = new BlockCapsule(wallet.getNowBlock()); | ||
| Assert.assertEquals("unexpected block number", expectedBlockNum, blockCapsule3.getNum()); | ||
|
|
||
| block = getSignedBlock(witnessCapsule.getAddress(), | ||
| nextScheduledTime(witnessCapsule.getAddress()), privateKey); | ||
| dbManager.pushBlock(new BlockCapsule(block)); | ||
|
|
||
| // scan note by ivk | ||
| byte[] receiverIvk = incomingViewingKey.getValue(); | ||
| DecryptNotes notes1 = wallet.scanNoteByIvk(0, 100, receiverIvk); | ||
| Assert.assertEquals(2, notes1.getNoteTxsCount()); | ||
|
|
||
| // scan note by ivk and mark | ||
| DecryptNotesMarked notes3 = wallet.scanAndMarkNoteByIvk(0, 100, receiverIvk, | ||
| fullViewingKey.getAk(), fullViewingKey.getNk()); | ||
| Assert.assertEquals(2, notes3.getNoteTxsCount()); | ||
|
|
||
| // scan note by ovk | ||
| DecryptNotes notes2 = wallet.scanNoteByOvk(0, 100, senderOvk); | ||
| Assert.assertEquals(2, notes2.getNoteTxsCount()); | ||
|
|
||
| // to spend received note above. | ||
| ZenTransactionBuilder builder2 = new ZenTransactionBuilder(wallet); | ||
|
|
||
| //query merkleinfo | ||
| OutputPointInfo.Builder request = OutputPointInfo.newBuilder(); | ||
| for (int i = 0; i < notes1.getNoteTxsCount(); i++) { | ||
| OutputPoint.Builder outPointBuild = OutputPoint.newBuilder(); | ||
| outPointBuild.setHash(ByteString.copyFrom(trxId)); | ||
| outPointBuild.setIndex(i); | ||
| request.addOutPoints(outPointBuild.build()); | ||
| } | ||
| request.setBlockNum(1); | ||
| IncrementalMerkleVoucherInfo merkleVoucherInfo = wallet | ||
| .getMerkleTreeVoucherInfo(request.build()); | ||
|
|
||
| //build spend proof. allow only one note in spend | ||
| ExpandedSpendingKey expsk2 = sk2.expandedSpendingKey(); | ||
| for (int i = 0; i < 1; i++) { | ||
| org.tron.api.GrpcAPI.Note grpcNote = notes1.getNoteTxs(i).getNote(); | ||
| PaymentAddress paymentAddress = KeyIo.decodePaymentAddress(grpcNote.getPaymentAddress()); | ||
| Note note2 = new Note(paymentAddress.getD(), | ||
| paymentAddress.getPkD(), | ||
| grpcNote.getValue(), | ||
| grpcNote.getRcm().toByteArray() | ||
| ); | ||
|
|
||
| IncrementalMerkleVoucherContainer voucher2 = | ||
| new IncrementalMerkleVoucherContainer( | ||
| new IncrementalMerkleVoucherCapsule(merkleVoucherInfo.getVouchers(i))); | ||
| byte[] anchor2 = voucher2.root().getContent().toByteArray(); | ||
| builder2.addSpend(expsk2, note2, anchor2, voucher2); | ||
| } | ||
|
|
||
| IncrementalMerkleVoucherContainer voucher2 = | ||
| new IncrementalMerkleVoucherContainer( | ||
| new IncrementalMerkleVoucherCapsule(merkleVoucherInfo.getVouchers(i))); | ||
| byte[] anchor2 = voucher2.root().getContent().toByteArray(); | ||
| builder2.addSpend(expsk2, note2, anchor2, voucher2); | ||
| //build output proof | ||
| SpendingKey sk3 = SpendingKey.random(); | ||
| FullViewingKey fvk3 = sk3.fullViewingKey(); | ||
| IncomingViewingKey ivk3 = fvk3.inViewingKey(); | ||
|
|
||
| DiversifierT d3 = DiversifierT.random(); | ||
| PaymentAddress paymentAddress3 = incomingViewingKey.address(d3).get(); | ||
| byte[] memo3 = org.tron.keystore.Wallet.generateRandomBytes(512); | ||
| builder2.addOutput(expsk2.getOvk(), paymentAddress3, | ||
| (1000 * 1000000L - wallet.getShieldedTransactionFee()) / 2 - wallet | ||
| .getShieldedTransactionFee(), memo3); | ||
|
|
||
| TransactionCapsule transactionCap2 = builder2.build(); | ||
| boolean ok2 = dbManager.pushTransaction(transactionCap2); | ||
| Assert.assertTrue(ok2); | ||
| } finally { | ||
| // DposTask.init() does not reset isRunning (it stays false after stop()), so force it back | ||
| // to true via reflection before restarting. | ||
| Field isRunning = DposTask.class.getDeclaredField("isRunning"); | ||
| isRunning.setAccessible(true); | ||
| isRunning.set(dposTask, true); | ||
| consensusService.start(); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [SHOULD]
However, This means the test can still affect subsequent tests running in the same Spring context. Consider either:
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, other testcases don't use
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [SHOULD] The test appears to work around a real production issue via reflection rather than fixing the root cause.
The actual fix seems to be a single line: isRunning = true;at the beginning of That would also allow the test to simply call As written, the underlying defect remains, and the test reaches into a private Recommend fixing
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The main code should not be modified solely to make the test cases pass.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The concern is not about modifying production code for the sake of a test. The test exposed a potential production issue: any If such a lifecycle transition cannot occur in production, then this can be considered a test-only concern and safely ignored. Otherwise, it may indicate a real bug in the service lifecycle handling.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This lifecycle transition |
||
| } | ||
| } | ||
|
|
||
| // Returns the earliest timestamp at which witnessAddr is the DPoS-scheduled producer, | ||
| // relative to the current chain head. Using this avoids relying on the genesis-only | ||
| // bypass in validBlock() (latestBlockHeaderNumber == 0) when prior tests have pushed blocks. | ||
| private long nextScheduledTime(ByteString witnessAddr) { | ||
| int size = chainBaseManager.getWitnessScheduleStore().getActiveWitnesses().size(); | ||
| for (long slot = 1; slot <= size; slot++) { | ||
| if (dposSlot.getScheduledWitness(slot).equals(witnessAddr)) { | ||
| return dposSlot.getTime(slot); | ||
| } | ||
| } | ||
|
|
||
| //build output proof | ||
| SpendingKey sk3 = SpendingKey.random(); | ||
| FullViewingKey fvk3 = sk3.fullViewingKey(); | ||
| IncomingViewingKey ivk3 = fvk3.inViewingKey(); | ||
|
|
||
| DiversifierT d3 = DiversifierT.random(); | ||
| PaymentAddress paymentAddress3 = incomingViewingKey.address(d3).get(); | ||
| byte[] memo3 = org.tron.keystore.Wallet.generateRandomBytes(512); | ||
| builder2.addOutput(expsk2.getOvk(), paymentAddress3, | ||
| (1000 * 1000000L - wallet.getShieldedTransactionFee()) / 2 - wallet | ||
| .getShieldedTransactionFee(), memo3); | ||
|
|
||
| TransactionCapsule transactionCap2 = builder2.build(); | ||
| boolean ok2 = dbManager.pushTransaction(transactionCap2); | ||
| Assert.assertTrue(ok2); | ||
| throw new IllegalStateException("No scheduled slot for witness within " | ||
| + size + " slots: " + ByteArray.toHexString(witnessAddr.toByteArray())); | ||
| } | ||
|
|
||
| @Test | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.