From 59cd40bda022d271ea8b51d16910e33c4c820578 Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Wed, 3 Jul 2024 18:01:07 +0300 Subject: [PATCH 01/20] Changed modifier to RC for v6.3.1 --- rskj-core/src/main/resources/version.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rskj-core/src/main/resources/version.properties b/rskj-core/src/main/resources/version.properties index 7010280dc27..da76564f104 100644 --- a/rskj-core/src/main/resources/version.properties +++ b/rskj-core/src/main/resources/version.properties @@ -1,2 +1,2 @@ -versionNumber='6.3.0' -modifier="ARROWHEAD" +versionNumber='6.3.1' +modifier="RC" From 28eb7f5326660cc9c45bdece2d90a849f6c91d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Dahlquist?= Date: Tue, 25 Jun 2024 17:11:32 -0300 Subject: [PATCH 02/20] Add test to check receiveHeader throws an error when adding block with too much work --- .../java/co/rsk/peg/BridgeSupportTest.java | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java index ed1aac76bb5..66273401d06 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java @@ -22,6 +22,7 @@ import co.rsk.bitcoinj.script.Script; import co.rsk.bitcoinj.script.ScriptBuilder; import co.rsk.bitcoinj.store.BlockStoreException; +import co.rsk.bitcoinj.store.BtcBlockStore; import co.rsk.bitcoinj.wallet.Wallet; import co.rsk.blockchain.utils.BlockGenerator; import co.rsk.peg.constants.*; @@ -44,11 +45,16 @@ import co.rsk.peg.vote.AddressBasedAuthorizer; import co.rsk.peg.whitelist.LockWhitelist; import co.rsk.peg.whitelist.OneOffWhiteListEntry; +import co.rsk.test.builders.BlockBuilder; import co.rsk.test.builders.BridgeSupportBuilder; +import co.rsk.util.Factory; +import co.rsk.util.HexUtils; import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.encoders.HexEncoder; import org.ethereum.TestUtils; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.config.blockchain.upgrades.ActivationConfig.ForBlock; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.*; @@ -6229,6 +6235,184 @@ void receiveHeader_block_exist_in_storage() throws IOException, BlockStoreExcept Assertions.assertEquals(-4, result); } + @Test + void receiveHeader_block_with_too_much_work() throws IOException, BlockStoreException { + BridgeConstants bridgeMainnetConstants = BridgeMainNetConstants.getInstance(); + ForBlock activations = ActivationConfigsForTest.all().forBlock(0); + Repository repository = createRepository(); + BridgeStorageProvider bridgeStorageProvider = new BridgeStorageProvider( + repository, + PrecompiledContracts.BRIDGE_ADDR, + bridgeMainnetConstants, + activations + ); + BridgeEventLogger bridgeEventLogger = mock(BridgeEventLogger.class); + BtcLockSenderProvider btcLockSenderProvider = mock(BtcLockSenderProvider.class); + PeginInstructionsProvider peginInstructionsProvider = mock(PeginInstructionsProvider.class); + Block block = mock(Block.class); + + Context btcContext = new Context(bridgeMainnetConstants.getBtcParams()); + + FederationSupport federationSupport = new FederationSupport(bridgeMainnetConstants, bridgeStorageProvider, block, activations); + + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + + BtcBlockStoreWithCache.Factory btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory( + bridgeMainnetConstants.getBtcParams(), + 100, + 100 + ); + + BtcBlockStoreWithCache btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); + + BtcBlock chainHead = new BtcBlock( + bridgeMainnetConstants.getBtcParams(), + HexUtils.stringHexToByteArray("00e00820925b77c9ff4d0036aa29f3238cde12e9af9d55c34ed30200000000000000000032a9fa3e12ef87a2327b55db6a16a1227bb381db8b269d90aa3a6e38cf39665f91b47766255d0317c1b1575f") + ); + SignatureCache signatureCache = mock(SignatureCache.class); + + BridgeSupport bs = new BridgeSupport( + bridgeMainnetConstants, + bridgeStorageProvider, + bridgeEventLogger, + btcLockSenderProvider, + peginInstructionsProvider, + repository, + block, + btcContext, + federationSupport, + feePerKbSupport, + btcBlockStoreFactory, + activations, + signatureCache + ); + + BtcBlock btcBlockToAdd = new BtcBlock( + bridgeMainnetConstants.getBtcParams(), + HexUtils.stringHexToByteArray("006001207ca158816ffc9d45b9ecd6a49ffbf3038f3646cf13fc01000000000000000000e0182ce7cc10db785b5fb2fb4314053f5b12cd6116168797cb461aa339fc725078b87766255d0317ba5261e2") + ); + + // To do: + // - create a new checkpoints file that loads up to the block before the issue + // - update the genesis federation to be right after the block with the issue (so the checkpoint used is the one with the issue) + + // Make the previous block tip of the chain +// StoredBlock parent = new StoredBlock(chainHead, chainHead.getWork().multiply(BigInteger.TEN), 849137); +// StoredBlock child = new StoredBlock(btcBlockToAdd, btcBlockToAdd.getWork(), 849138); +// btcBlockStoreWithCache.put(parent); +// btcBlockStoreWithCache.setChainHead(parent); +// btcBlockStoreWithCache.put(child); +// repository.save(); +// assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), chainHead.getHash()); + + bs.receiveHeader(btcBlockToAdd); + assertEquals(bs.getBtcBlockchainBestChainHeight(), 849138); + + // Call a second time to trigger ensureBtcBlockStore + bs = new BridgeSupport( + bridgeMainnetConstants, + bridgeStorageProvider, + bridgeEventLogger, + btcLockSenderProvider, + peginInstructionsProvider, + repository, + block, + btcContext, + federationSupport, + feePerKbSupport, + new RepositoryBtcBlockStoreWithCache.Factory( + bridgeMainnetConstants.getBtcParams(), + 100, + 100 + ), + activations, + signatureCache + ); + bs.receiveHeader(btcBlockToAdd); + + } + + @Test + void receiveHeader_withExceededChainWork_returnsReceiveHeaderUnexpectedException() throws IOException, BlockStoreException { + // Arrange - recreate the context + BridgeConstants bridgeMainnetConstants = BridgeMainNetConstants.getInstance(); + Context btcContext = new Context(bridgeMainnetConstants.getBtcParams()); + + BridgeEventLogger bridgeEventLogger = mock(BridgeEventLogger.class); + BtcLockSenderProvider btcLockSenderProvider = mock(BtcLockSenderProvider.class); + PeginInstructionsProvider peginInstructionsProvider = mock(PeginInstructionsProvider.class); + Block block = mock(Block.class); + + ActivationConfig.ForBlock activations = ActivationConfigsForTest.all().forBlock(0); + Repository repository = createRepository(); + BridgeStorageProvider bridgeStorageProvider = new BridgeStorageProvider( + repository, + PrecompiledContracts.BRIDGE_ADDR, + bridgeMainnetConstants, + activations + ); + FederationSupport federationSupport = new FederationSupport(bridgeMainnetConstants, bridgeStorageProvider, block, activations); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + SignatureCache signatureCache = mock(SignatureCache.class); + + BtcBlockStoreWithCache.Factory btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory( + bridgeMainnetConstants.getBtcParams(), + 100, + 100 + ); + BridgeSupport bridgeSupport = new BridgeSupport( + bridgeMainnetConstants, + bridgeStorageProvider, + bridgeEventLogger, + btcLockSenderProvider, + peginInstructionsProvider, + repository, + block, + btcContext, + federationSupport, + feePerKbSupport, + btcBlockStoreFactory, + activations, + signatureCache + ); + BtcBlockStoreWithCache btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); + + // + // + // Act - add the problematic block and the previous one + // As of block 849138 chainWork has reached a value of 800028897aa1dce163ead2cf, + // that is 39614272687832008485268804303 in bigInt + BigInteger tooMuchWork = new BigInteger("39614272687832008485268804303"); + BigInteger difficultyForBlock = new BigInteger("-359387998867170497083477"); // this is (minus) the difficulty for each block + + // Create the previous block tip of the chain + String previousBlockHeader = "00e00820925b77c9ff4d0036aa29f3238cde12e9af9d55c34ed30200000000000000000032a9fa3e12ef87a2327b55db6a16a1227bb381db8b269d90aa3a6e38cf39665f91b47766255d0317c1b1575f"; + BtcBlock previousBlock = new BtcBlock( + bridgeMainnetConstants.getBtcParams(), + HexUtils.stringHexToByteArray(previousBlockHeader) + ); + // we have to set it with its accumulated difficulty to recreate the real scenario + // the chainWork for block 849137 should be the work reached in 849138, minus the difficulty from the block 849138 itself + StoredBlock parent = new StoredBlock(previousBlock, tooMuchWork.add(difficultyForBlock), 849137); + + // save previous block and assert + btcBlockStoreWithCache.put(parent); + btcBlockStoreWithCache.setChainHead(parent); + repository.save(); + assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), previousBlock.getHash()); + + // Create problematic block + String blockWithTooMuchWorkHeader = "006001207ca158816ffc9d45b9ecd6a49ffbf3038f3646cf13fc01000000000000000000e0182ce7cc10db785b5fb2fb4314053f5b12cd6116168797cb461aa339fc725078b87766255d0317ba5261e2"; + BtcBlock btcBlockWithTooMuchWork = new BtcBlock( + bridgeMainnetConstants.getBtcParams(), + HexUtils.stringHexToByteArray(blockWithTooMuchWorkHeader) + ); + + // assert that receiveHeader for the block with too much work throws a (handled) error + Integer RECEIVE_HEADER_UNEXPECTED_EXCEPTION = -99; + assertThat(bridgeSupport.receiveHeader(btcBlockWithTooMuchWork), is(RECEIVE_HEADER_UNEXPECTED_EXCEPTION)); + } + private void assertRefundInProcessPegInVersionLegacy( boolean isWhitelisted, boolean mockLockingCap, From b1698888cc8fa6d76db546edf72e91dbeeab931a Mon Sep 17 00:00:00 2001 From: julia-zack Date: Wed, 26 Jun 2024 15:35:13 -0300 Subject: [PATCH 03/20] Add rskip434 to config files --- .../org/ethereum/config/blockchain/upgrades/ConsensusRule.java | 1 + rskj-core/src/main/resources/config/main.conf | 3 +++ rskj-core/src/main/resources/config/regtest.conf | 3 ++- rskj-core/src/main/resources/config/testnet.conf | 3 ++- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java index f4a4375f5a3..72b787537ea 100644 --- a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java +++ b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/ConsensusRule.java @@ -94,6 +94,7 @@ public enum ConsensusRule { RSKIP415("rskip415"), RSKIP417("rskip417"), RSKIP428("rskip428"), + RSKIP434("rskip434") ; private String configKey; diff --git a/rskj-core/src/main/resources/config/main.conf b/rskj-core/src/main/resources/config/main.conf index e36939f99a2..268a17ac80a 100644 --- a/rskj-core/src/main/resources/config/main.conf +++ b/rskj-core/src/main/resources/config/main.conf @@ -14,6 +14,9 @@ blockchain.config { fingerroot500 = 5468000, arrowhead600 = 6223700, lovell700 = -1 + }, + consensusRules = { + rskip434 = -1 } } diff --git a/rskj-core/src/main/resources/config/regtest.conf b/rskj-core/src/main/resources/config/regtest.conf index d0b95b4036c..1d2a5cd86ee 100644 --- a/rskj-core/src/main/resources/config/regtest.conf +++ b/rskj-core/src/main/resources/config/regtest.conf @@ -17,7 +17,8 @@ blockchain.config { }, consensusRules = { rskip97 = -1 # disable orchid difficulty drop - rskipUMM = 1 + rskipUMM = 1, + rskip434 = -1 } } diff --git a/rskj-core/src/main/resources/config/testnet.conf b/rskj-core/src/main/resources/config/testnet.conf index d0da9e12899..d6d4f8cf7a4 100644 --- a/rskj-core/src/main/resources/config/testnet.conf +++ b/rskj-core/src/main/resources/config/testnet.conf @@ -19,7 +19,8 @@ blockchain.config { rskip97 = -1, # disable orchid difficulty drop rskip132 = 43550, # enable recalculted receive headers cost rskip284 = 2581800, - rskip290 = 2581800 + rskip290 = 2581800, + rskip434 = -1 } } From e40f01de8f5d54ee63dd25f4753d6298497e72bc Mon Sep 17 00:00:00 2001 From: julia-zack Date: Wed, 26 Jun 2024 15:46:50 -0300 Subject: [PATCH 04/20] Add patch to receiveHeader Add unit test for before and after rskip434 Add fix for receiveHeaders too Replace too much work check with height check Add tests for receiveHeaders and refactor Correct test name --- .../main/java/co/rsk/peg/BridgeSupport.java | 20 ++ .../java/co/rsk/peg/BridgeSupportTest.java | 283 +++++++----------- 2 files changed, 135 insertions(+), 168 deletions(-) diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java index 65a1fe491d6..9f7ea595842 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -211,6 +211,11 @@ public void receiveHeaders(BtcBlock[] headers) throws IOException, BlockStoreExc Context.propagate(btcContext); this.ensureBtcBlockChain(); for (BtcBlock header : headers) { + StoredBlock previousBlock = btcBlockStore.get(header.getPrevBlockHash()); + if (cannotProcessBlock(header, previousBlock)) { + logger.warn("[receiveHeader] Header {} has too much work to be processed", header.getHash()); + break; + } try { btcBlockChain.add(header); } catch (Exception e) { @@ -253,6 +258,11 @@ public Integer receiveHeader(BtcBlock header) throws IOException, BlockStoreExce return RECEIVE_HEADER_BLOCK_TOO_OLD; } + if (cannotProcessBlock(header, previousBlock)) { + logger.warn("[receiveHeader] Header {} has too much work to be processed", header.getHash()); + return RECEIVE_HEADER_UNEXPECTED_EXCEPTION; + } + try { btcBlockChain.add(header); } catch (Exception e) { @@ -265,6 +275,16 @@ public Integer receiveHeader(BtcBlock header) throws IOException, BlockStoreExce return 0; } + private boolean cannotProcessBlock(BtcBlock block, StoredBlock previousBlock) { + StoredBlock blockToAdd = previousBlock.build(block); + int errorHeight = 849138; + + boolean networkIsMainnet = btcContext.getParams().equals(NetworkParameters.fromID(NetworkParameters.ID_MAINNET)); + return blockToAdd.getHeight() >= errorHeight + && networkIsMainnet + && !activations.isActive(ConsensusRule.RSKIP434); + } + /** * Get the wallet for the currently active federation * @return A BTC wallet for the currently active federation diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java index 66273401d06..dde76677095 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java @@ -22,7 +22,6 @@ import co.rsk.bitcoinj.script.Script; import co.rsk.bitcoinj.script.ScriptBuilder; import co.rsk.bitcoinj.store.BlockStoreException; -import co.rsk.bitcoinj.store.BtcBlockStore; import co.rsk.bitcoinj.wallet.Wallet; import co.rsk.blockchain.utils.BlockGenerator; import co.rsk.peg.constants.*; @@ -45,16 +44,12 @@ import co.rsk.peg.vote.AddressBasedAuthorizer; import co.rsk.peg.whitelist.LockWhitelist; import co.rsk.peg.whitelist.OneOffWhiteListEntry; -import co.rsk.test.builders.BlockBuilder; import co.rsk.test.builders.BridgeSupportBuilder; -import co.rsk.util.Factory; import co.rsk.util.HexUtils; import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.encoders.HexEncoder; import org.ethereum.TestUtils; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; -import org.ethereum.config.blockchain.upgrades.ActivationConfig.ForBlock; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.*; @@ -62,9 +57,7 @@ import org.ethereum.crypto.HashUtil; import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.exception.VMException; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -6235,182 +6228,136 @@ void receiveHeader_block_exist_in_storage() throws IOException, BlockStoreExcept Assertions.assertEquals(-4, result); } - @Test - void receiveHeader_block_with_too_much_work() throws IOException, BlockStoreException { + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + @Tag("test chain work before and after rskip 434") + class ChainWorkTests { + ActivationConfig.ForBlock activations; BridgeConstants bridgeMainnetConstants = BridgeMainNetConstants.getInstance(); - ForBlock activations = ActivationConfigsForTest.all().forBlock(0); - Repository repository = createRepository(); - BridgeStorageProvider bridgeStorageProvider = new BridgeStorageProvider( - repository, - PrecompiledContracts.BRIDGE_ADDR, - bridgeMainnetConstants, - activations - ); - BridgeEventLogger bridgeEventLogger = mock(BridgeEventLogger.class); - BtcLockSenderProvider btcLockSenderProvider = mock(BtcLockSenderProvider.class); - PeginInstructionsProvider peginInstructionsProvider = mock(PeginInstructionsProvider.class); - Block block = mock(Block.class); - - Context btcContext = new Context(bridgeMainnetConstants.getBtcParams()); - - FederationSupport federationSupport = new FederationSupport(bridgeMainnetConstants, bridgeStorageProvider, block, activations); + Repository repository; + BridgeStorageProvider bridgeStorageProvider; + BtcBlockStoreWithCache.Factory btcBlockStoreFactory; + BtcBlockStoreWithCache btcBlockStoreWithCache; + BridgeSupportBuilder bridgeSupportBuilder = new BridgeSupportBuilder(); + BridgeSupport bridgeSupport; + + BtcBlock previousBlock; + BtcBlock btcBlockWithTooMuchWork; + + @BeforeEach + void setUp() throws BlockStoreException { + activations = ActivationConfigsForTest.all().forBlock(0); + repository = createRepository(); + bridgeStorageProvider = new BridgeStorageProvider( + repository, + PrecompiledContracts.BRIDGE_ADDR, + bridgeMainnetConstants, + activations + ); - FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory(bridgeMainnetConstants.getBtcParams(), 100, 100); + btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); + + // As of block 849138 chainWork has reached a value of 800028897aa1dce163ead2cf, + // that is 39614272687832008485268804303 in bigInt + // the chainWork for block 849137 should be the work reached in 849138, minus the difficulty from the block 849138 itself + BigInteger tooMuchWork = new BigInteger("39614272687832008485268804303"); + BigInteger difficultyForBlock = new BigInteger("-359387998867170497083477"); // this is (minus) the difficulty for each block + BigInteger previousBlockCumulativeDifficulty = tooMuchWork.add(difficultyForBlock); + + // Create the previous block tip of the chain + String previousBlockHeader = "00e00820925b77c9ff4d0036aa29f3238cde12e9af9d55c34ed30200000000000000000032a9fa3e12ef87a2327b55db6a16a1227bb381db8b269d90aa3a6e38cf39665f91b47766255d0317c1b1575f"; + previousBlock = new BtcBlock(bridgeMainnetConstants.getBtcParams(), HexUtils.stringHexToByteArray(previousBlockHeader)); + + // we have to save it with its cumulative difficulty to recreate the real scenario + StoredBlock parent = new StoredBlock(previousBlock, previousBlockCumulativeDifficulty, 849137); + // save block + btcBlockStoreWithCache.put(parent); + btcBlockStoreWithCache.setChainHead(parent); + repository.save(); + + // Create problematic block + String blockWithTooMuchWorkHeader = "006001207ca158816ffc9d45b9ecd6a49ffbf3038f3646cf13fc01000000000000000000e0182ce7cc10db785b5fb2fb4314053f5b12cd6116168797cb461aa339fc725078b87766255d0317ba5261e2"; + btcBlockWithTooMuchWork = new BtcBlock(bridgeMainnetConstants.getBtcParams(), HexUtils.stringHexToByteArray(blockWithTooMuchWorkHeader)); + } - BtcBlockStoreWithCache.Factory btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory( - bridgeMainnetConstants.getBtcParams(), - 100, - 100 - ); + @Test + void receiveHeader_beforeRSKIP434_returnsUnexpectedExceptionResponseCode() throws BlockStoreException, IOException { + activations = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP434).forBlock(0); - BtcBlockStoreWithCache btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); + // first assert that previous block was correctly saved + assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), previousBlock.getHash()); - BtcBlock chainHead = new BtcBlock( - bridgeMainnetConstants.getBtcParams(), - HexUtils.stringHexToByteArray("00e00820925b77c9ff4d0036aa29f3238cde12e9af9d55c34ed30200000000000000000032a9fa3e12ef87a2327b55db6a16a1227bb381db8b269d90aa3a6e38cf39665f91b47766255d0317c1b1575f") - ); - SignatureCache signatureCache = mock(SignatureCache.class); + bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeMainnetConstants) + .withProvider(bridgeStorageProvider) + .withRepository(repository) + .withBtcBlockStoreFactory(btcBlockStoreFactory) + .withActivations(activations) + .build(); - BridgeSupport bs = new BridgeSupport( - bridgeMainnetConstants, - bridgeStorageProvider, - bridgeEventLogger, - btcLockSenderProvider, - peginInstructionsProvider, - repository, - block, - btcContext, - federationSupport, - feePerKbSupport, - btcBlockStoreFactory, - activations, - signatureCache - ); + // assert receive header returns an exception and does not save the block + Integer RECEIVE_HEADER_UNEXPECTED_EXCEPTION = -99; + assertThat(bridgeSupport.receiveHeader(btcBlockWithTooMuchWork), is(RECEIVE_HEADER_UNEXPECTED_EXCEPTION)); + assertNull(btcBlockStoreWithCache.get(btcBlockWithTooMuchWork.getHash())); + } - BtcBlock btcBlockToAdd = new BtcBlock( - bridgeMainnetConstants.getBtcParams(), - HexUtils.stringHexToByteArray("006001207ca158816ffc9d45b9ecd6a49ffbf3038f3646cf13fc01000000000000000000e0182ce7cc10db785b5fb2fb4314053f5b12cd6116168797cb461aa339fc725078b87766255d0317ba5261e2") - ); + @Test + void receiveHeader_afterRSKIP434_returnsSuccessful() throws BlockStoreException, IOException { + // first assert that previous block was correctly saved + assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), previousBlock.getHash()); - // To do: - // - create a new checkpoints file that loads up to the block before the issue - // - update the genesis federation to be right after the block with the issue (so the checkpoint used is the one with the issue) + bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeMainnetConstants) + .withProvider(bridgeStorageProvider) + .withRepository(repository) + .withBtcBlockStoreFactory(btcBlockStoreFactory) + .withActivations(activations) + .build(); - // Make the previous block tip of the chain -// StoredBlock parent = new StoredBlock(chainHead, chainHead.getWork().multiply(BigInteger.TEN), 849137); -// StoredBlock child = new StoredBlock(btcBlockToAdd, btcBlockToAdd.getWork(), 849138); -// btcBlockStoreWithCache.put(parent); -// btcBlockStoreWithCache.setChainHead(parent); -// btcBlockStoreWithCache.put(child); -// repository.save(); -// assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), chainHead.getHash()); + // assert receive header returns successful response and saves the block + Integer RECEIVE_HEADER_SUCCESSFUL = 0; + assertThat(bridgeSupport.receiveHeader(btcBlockWithTooMuchWork), is(RECEIVE_HEADER_SUCCESSFUL)); + assertNotNull(btcBlockStoreWithCache.get(btcBlockWithTooMuchWork.getHash())); + } - bs.receiveHeader(btcBlockToAdd); - assertEquals(bs.getBtcBlockchainBestChainHeight(), 849138); + @Test + void receiveHeaders_beforeRSKIP434_catchesTheException() throws BlockStoreException, IOException { + activations = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP434).forBlock(0); - // Call a second time to trigger ensureBtcBlockStore - bs = new BridgeSupport( - bridgeMainnetConstants, - bridgeStorageProvider, - bridgeEventLogger, - btcLockSenderProvider, - peginInstructionsProvider, - repository, - block, - btcContext, - federationSupport, - feePerKbSupport, - new RepositoryBtcBlockStoreWithCache.Factory( - bridgeMainnetConstants.getBtcParams(), - 100, - 100 - ), - activations, - signatureCache - ); - bs.receiveHeader(btcBlockToAdd); + // first assert that previous block was correctly saved + assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), previousBlock.getHash()); - } + bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeMainnetConstants) + .withProvider(bridgeStorageProvider) + .withRepository(repository) + .withBtcBlockStoreFactory(btcBlockStoreFactory) + .withActivations(activations) + .build(); - @Test - void receiveHeader_withExceededChainWork_returnsReceiveHeaderUnexpectedException() throws IOException, BlockStoreException { - // Arrange - recreate the context - BridgeConstants bridgeMainnetConstants = BridgeMainNetConstants.getInstance(); - Context btcContext = new Context(bridgeMainnetConstants.getBtcParams()); + // assert receive headers does not save the block + bridgeSupport.receiveHeaders(new BtcBlock[] { btcBlockWithTooMuchWork }); + assertNull(btcBlockStoreWithCache.get(btcBlockWithTooMuchWork.getHash())); + } - BridgeEventLogger bridgeEventLogger = mock(BridgeEventLogger.class); - BtcLockSenderProvider btcLockSenderProvider = mock(BtcLockSenderProvider.class); - PeginInstructionsProvider peginInstructionsProvider = mock(PeginInstructionsProvider.class); - Block block = mock(Block.class); + @Test + void receiveHeaders_afterRSKIP434_savesTheBlock() throws BlockStoreException, IOException { + // first assert that previous block was correctly saved + assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), previousBlock.getHash()); - ActivationConfig.ForBlock activations = ActivationConfigsForTest.all().forBlock(0); - Repository repository = createRepository(); - BridgeStorageProvider bridgeStorageProvider = new BridgeStorageProvider( - repository, - PrecompiledContracts.BRIDGE_ADDR, - bridgeMainnetConstants, - activations - ); - FederationSupport federationSupport = new FederationSupport(bridgeMainnetConstants, bridgeStorageProvider, block, activations); - FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); - SignatureCache signatureCache = mock(SignatureCache.class); + bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeMainnetConstants) + .withProvider(bridgeStorageProvider) + .withRepository(repository) + .withBtcBlockStoreFactory(btcBlockStoreFactory) + .withActivations(activations) + .build(); - BtcBlockStoreWithCache.Factory btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory( - bridgeMainnetConstants.getBtcParams(), - 100, - 100 - ); - BridgeSupport bridgeSupport = new BridgeSupport( - bridgeMainnetConstants, - bridgeStorageProvider, - bridgeEventLogger, - btcLockSenderProvider, - peginInstructionsProvider, - repository, - block, - btcContext, - federationSupport, - feePerKbSupport, - btcBlockStoreFactory, - activations, - signatureCache - ); - BtcBlockStoreWithCache btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); - - // - // - // Act - add the problematic block and the previous one - // As of block 849138 chainWork has reached a value of 800028897aa1dce163ead2cf, - // that is 39614272687832008485268804303 in bigInt - BigInteger tooMuchWork = new BigInteger("39614272687832008485268804303"); - BigInteger difficultyForBlock = new BigInteger("-359387998867170497083477"); // this is (minus) the difficulty for each block - - // Create the previous block tip of the chain - String previousBlockHeader = "00e00820925b77c9ff4d0036aa29f3238cde12e9af9d55c34ed30200000000000000000032a9fa3e12ef87a2327b55db6a16a1227bb381db8b269d90aa3a6e38cf39665f91b47766255d0317c1b1575f"; - BtcBlock previousBlock = new BtcBlock( - bridgeMainnetConstants.getBtcParams(), - HexUtils.stringHexToByteArray(previousBlockHeader) - ); - // we have to set it with its accumulated difficulty to recreate the real scenario - // the chainWork for block 849137 should be the work reached in 849138, minus the difficulty from the block 849138 itself - StoredBlock parent = new StoredBlock(previousBlock, tooMuchWork.add(difficultyForBlock), 849137); - - // save previous block and assert - btcBlockStoreWithCache.put(parent); - btcBlockStoreWithCache.setChainHead(parent); - repository.save(); - assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), previousBlock.getHash()); - - // Create problematic block - String blockWithTooMuchWorkHeader = "006001207ca158816ffc9d45b9ecd6a49ffbf3038f3646cf13fc01000000000000000000e0182ce7cc10db785b5fb2fb4314053f5b12cd6116168797cb461aa339fc725078b87766255d0317ba5261e2"; - BtcBlock btcBlockWithTooMuchWork = new BtcBlock( - bridgeMainnetConstants.getBtcParams(), - HexUtils.stringHexToByteArray(blockWithTooMuchWorkHeader) - ); - - // assert that receiveHeader for the block with too much work throws a (handled) error - Integer RECEIVE_HEADER_UNEXPECTED_EXCEPTION = -99; - assertThat(bridgeSupport.receiveHeader(btcBlockWithTooMuchWork), is(RECEIVE_HEADER_UNEXPECTED_EXCEPTION)); + // assert block was correctly saved + bridgeSupport.receiveHeaders(new BtcBlock[] { btcBlockWithTooMuchWork }); + assertNotNull(btcBlockStoreWithCache.get(btcBlockWithTooMuchWork.getHash())); + } } private void assertRefundInProcessPegInVersionLegacy( From b519943c3b782beef258d3665fc088cb9a118bdb Mon Sep 17 00:00:00 2001 From: julia-zack Date: Thu, 27 Jun 2024 14:23:53 -0300 Subject: [PATCH 05/20] Add block with too much chain work height in BridgeConstants Refactor and use value from bridge constants --- .../src/main/java/co/rsk/peg/BridgeSupport.java | 17 ++++++++--------- .../co/rsk/peg/constants/BridgeConstants.java | 3 +++ .../peg/constants/BridgeMainNetConstants.java | 2 ++ .../peg/constants/BridgeRegTestConstants.java | 2 ++ .../peg/constants/BridgeTestNetConstants.java | 2 ++ 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java index 9f7ea595842..af4ce00d52a 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -211,9 +211,9 @@ public void receiveHeaders(BtcBlock[] headers) throws IOException, BlockStoreExc Context.propagate(btcContext); this.ensureBtcBlockChain(); for (BtcBlock header : headers) { - StoredBlock previousBlock = btcBlockStore.get(header.getPrevBlockHash()); - if (cannotProcessBlock(header, previousBlock)) { - logger.warn("[receiveHeader] Header {} has too much work to be processed", header.getHash()); + StoredBlock previousBlock = btcBlockStore.get(header.getPrevBlockHash()); // we assume previous block was already saved + if (cannotProcessNextBlock(previousBlock)) { + logger.warn("[receiveHeaders] Header {} has too much work to be processed", header.getHash()); break; } try { @@ -258,7 +258,7 @@ public Integer receiveHeader(BtcBlock header) throws IOException, BlockStoreExce return RECEIVE_HEADER_BLOCK_TOO_OLD; } - if (cannotProcessBlock(header, previousBlock)) { + if (cannotProcessNextBlock(previousBlock)) { logger.warn("[receiveHeader] Header {} has too much work to be processed", header.getHash()); return RECEIVE_HEADER_UNEXPECTED_EXCEPTION; } @@ -275,12 +275,11 @@ public Integer receiveHeader(BtcBlock header) throws IOException, BlockStoreExce return 0; } - private boolean cannotProcessBlock(BtcBlock block, StoredBlock previousBlock) { - StoredBlock blockToAdd = previousBlock.build(block); - int errorHeight = 849138; - + private boolean cannotProcessNextBlock(StoredBlock previousBlock) { + int nextBlockHeight = previousBlock.getHeight() + 1; boolean networkIsMainnet = btcContext.getParams().equals(NetworkParameters.fromID(NetworkParameters.ID_MAINNET)); - return blockToAdd.getHeight() >= errorHeight + + return nextBlockHeight >= bridgeConstants.getBlockWithTooMuchChainWorkHeight() && networkIsMainnet && !activations.isActive(ConsensusRule.RSKIP434); } diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeConstants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeConstants.java index 0a629ec7431..8c3739a091f 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeConstants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeConstants.java @@ -87,6 +87,7 @@ public abstract class BridgeConstants { protected int btcHeightWhenPegoutTxIndexActivates; protected int pegoutTxIndexGracePeriodInBtcBlocks; + protected int blockWithTooMuchChainWorkHeight; public NetworkParameters getBtcParams() { return NetworkParameters.fromID(btcParamsString); @@ -197,4 +198,6 @@ public int getBtcHeightWhenPegoutTxIndexActivates() { public int getPegoutTxIndexGracePeriodInBtcBlocks() { return pegoutTxIndexGracePeriodInBtcBlocks; } + + public int getBlockWithTooMuchChainWorkHeight() { return blockWithTooMuchChainWorkHeight; } } diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeMainNetConstants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeMainNetConstants.java index 1a023ac24af..df065348649 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeMainNetConstants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeMainNetConstants.java @@ -124,6 +124,8 @@ private BridgeMainNetConstants() { btcHeightWhenPegoutTxIndexActivates = 837_589; // Estimated date Wed, 03 Apr 2024 15:00:00 GMT. 832,430 was the block number at time of calculation pegoutTxIndexGracePeriodInBtcBlocks = 4_320; // 30 days in BTC blocks (considering 1 block every 10 minutes) + + blockWithTooMuchChainWorkHeight = 849_138; } public static BridgeMainNetConstants getInstance() { diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeRegTestConstants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeRegTestConstants.java index 38d58ab24f0..884f0252221 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeRegTestConstants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeRegTestConstants.java @@ -144,6 +144,8 @@ public BridgeRegTestConstants(List federationPublicKeys) { btcHeightWhenPegoutTxIndexActivates = 250; pegoutTxIndexGracePeriodInBtcBlocks = 100; + + blockWithTooMuchChainWorkHeight = Integer.MAX_VALUE; } public static BridgeRegTestConstants getInstance() { diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNetConstants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNetConstants.java index 0b51e75feee..60b4cbcd4a5 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNetConstants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNetConstants.java @@ -143,6 +143,8 @@ public class BridgeTestNetConstants extends BridgeConstants { btcHeightWhenPegoutTxIndexActivates = 2_589_553; // Estimated date Wed, 20 Mar 2024 15:00:00 GMT. 2,579,823 was the block number at time of calculation pegoutTxIndexGracePeriodInBtcBlocks = 1_440; // 10 days in BTC blocks (considering 1 block every 10 minutes) + + blockWithTooMuchChainWorkHeight = Integer.MAX_VALUE; } public static BridgeTestNetConstants getInstance() { From d6b3d340b8cc7ea8daa50ad5e176ca8711fede1a Mon Sep 17 00:00:00 2001 From: julia-zack Date: Thu, 27 Jun 2024 14:25:02 -0300 Subject: [PATCH 06/20] Add tests for receiveHeaders with many blocks. Refactor Refactor Put verification inside try to avoid npe --- .../main/java/co/rsk/peg/BridgeSupport.java | 10 +- .../java/co/rsk/peg/BridgeSupportTest.java | 187 ++++++++++++------ 2 files changed, 131 insertions(+), 66 deletions(-) diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java index af4ce00d52a..b97ecfde42e 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -211,12 +211,12 @@ public void receiveHeaders(BtcBlock[] headers) throws IOException, BlockStoreExc Context.propagate(btcContext); this.ensureBtcBlockChain(); for (BtcBlock header : headers) { - StoredBlock previousBlock = btcBlockStore.get(header.getPrevBlockHash()); // we assume previous block was already saved - if (cannotProcessNextBlock(previousBlock)) { - logger.warn("[receiveHeaders] Header {} has too much work to be processed", header.getHash()); - break; - } try { + StoredBlock previousBlock = btcBlockStore.get(header.getPrevBlockHash()); + if (cannotProcessNextBlock(previousBlock)) { + logger.warn("[receiveHeaders] Header {} has too much work to be processed", header.getHash()); + break; + } btcBlockChain.add(header); } catch (Exception e) { // If we try to add an orphan header bitcoinj throws an exception diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java index dde76677095..b20d0b38c46 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java @@ -6241,53 +6241,48 @@ class ChainWorkTests { BridgeSupportBuilder bridgeSupportBuilder = new BridgeSupportBuilder(); BridgeSupport bridgeSupport; - BtcBlock previousBlock; - BtcBlock btcBlockWithTooMuchWork; + BtcBlock block849134; + BtcBlock block849135; + BtcBlock block849136; + BtcBlock block849137; + BtcBlock blockWithTooMuchWork; + BtcBlock block849139; @BeforeEach - void setUp() throws BlockStoreException { + void setUp() { activations = ActivationConfigsForTest.all().forBlock(0); repository = createRepository(); - bridgeStorageProvider = new BridgeStorageProvider( - repository, - PrecompiledContracts.BRIDGE_ADDR, - bridgeMainnetConstants, - activations - ); - btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory(bridgeMainnetConstants.getBtcParams(), 100, 100); - btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); - // As of block 849138 chainWork has reached a value of 800028897aa1dce163ead2cf, - // that is 39614272687832008485268804303 in bigInt - // the chainWork for block 849137 should be the work reached in 849138, minus the difficulty from the block 849138 itself - BigInteger tooMuchWork = new BigInteger("39614272687832008485268804303"); - BigInteger difficultyForBlock = new BigInteger("-359387998867170497083477"); // this is (minus) the difficulty for each block - BigInteger previousBlockCumulativeDifficulty = tooMuchWork.add(difficultyForBlock); - - // Create the previous block tip of the chain - String previousBlockHeader = "00e00820925b77c9ff4d0036aa29f3238cde12e9af9d55c34ed30200000000000000000032a9fa3e12ef87a2327b55db6a16a1227bb381db8b269d90aa3a6e38cf39665f91b47766255d0317c1b1575f"; - previousBlock = new BtcBlock(bridgeMainnetConstants.getBtcParams(), HexUtils.stringHexToByteArray(previousBlockHeader)); - - // we have to save it with its cumulative difficulty to recreate the real scenario - StoredBlock parent = new StoredBlock(previousBlock, previousBlockCumulativeDifficulty, 849137); - // save block - btcBlockStoreWithCache.put(parent); - btcBlockStoreWithCache.setChainHead(parent); - repository.save(); + String block849134Header = "0080b92c24f123130ae29e899f0cab72653722e54cdf3b30445202000000000000000000c72ead65a3b78ab637d1876c00414a77e47bcc5b52667ac1e573633563bea5a695aa7766255d031728d182a8"; + block849134 = new BtcBlock(bridgeMainnetConstants.getBtcParams(), HexUtils.stringHexToByteArray(block849134Header)); + + String block849135Header = "00004020bf67910b5d3996ee594848b482ee84d0e28c97a9a2d601000000000000000000865e218552bb92df36c962f5163e84a6c2542584fb36be2fa8b2a4246c73a701f1ae7766255d031791836b22"; + block849135 = new BtcBlock(bridgeMainnetConstants.getBtcParams(), HexUtils.stringHexToByteArray(block849135Header)); + + String block849136Header = "0000003a796f8b7a9d6ba6e13064e7c64e94570f877170262f1f0200000000000000000036b2ab17565a24a9be4626ca801cb31f91232034ba848295475f931a58dd5446e5b07766255d03173b01a491"; + block849136 = new BtcBlock(bridgeMainnetConstants.getBtcParams(), HexUtils.stringHexToByteArray(block849136Header)); + + String block849137Header = "00e00820925b77c9ff4d0036aa29f3238cde12e9af9d55c34ed30200000000000000000032a9fa3e12ef87a2327b55db6a16a1227bb381db8b269d90aa3a6e38cf39665f91b47766255d0317c1b1575f"; + block849137 = new BtcBlock(bridgeMainnetConstants.getBtcParams(), HexUtils.stringHexToByteArray(block849137Header)); - // Create problematic block String blockWithTooMuchWorkHeader = "006001207ca158816ffc9d45b9ecd6a49ffbf3038f3646cf13fc01000000000000000000e0182ce7cc10db785b5fb2fb4314053f5b12cd6116168797cb461aa339fc725078b87766255d0317ba5261e2"; - btcBlockWithTooMuchWork = new BtcBlock(bridgeMainnetConstants.getBtcParams(), HexUtils.stringHexToByteArray(blockWithTooMuchWorkHeader)); + blockWithTooMuchWork = new BtcBlock(bridgeMainnetConstants.getBtcParams(), HexUtils.stringHexToByteArray(blockWithTooMuchWorkHeader)); + + String block849139Header = "00a0b625ffa2f7cbf95219fc74c3db38f84ae265784bc1417c71020000000000000000008e5b319a229376089f4a7b77c90ed90ac19a0532fc4c62426f5a5931ee7e3e8dd2c67766255d03171e91a015"; + block849139 = new BtcBlock(bridgeMainnetConstants.getBtcParams(), HexUtils.stringHexToByteArray(block849139Header)); } @Test - void receiveHeader_beforeRSKIP434_returnsUnexpectedExceptionResponseCode() throws BlockStoreException, IOException { + void receiveHeader_beforeRSKIP434_returnsUnexpectedExceptionResponseCodeAndDoesNotSaveTheBlock() throws BlockStoreException, IOException { + // rskip434 should be inactive activations = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP434).forBlock(0); - - // first assert that previous block was correctly saved - assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), previousBlock.getHash()); - + bridgeStorageProvider = new BridgeStorageProvider( + repository, + PrecompiledContracts.BRIDGE_ADDR, + bridgeMainnetConstants, + activations + ); bridgeSupport = bridgeSupportBuilder .withBridgeConstants(bridgeMainnetConstants) .withProvider(bridgeStorageProvider) @@ -6295,18 +6290,34 @@ void receiveHeader_beforeRSKIP434_returnsUnexpectedExceptionResponseCode() throw .withBtcBlockStoreFactory(btcBlockStoreFactory) .withActivations(activations) .build(); + btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); + + // Create block with too much work parent with cumulative difficulty + BigInteger block849137ChainWork = new BigInteger("00000000000000000000000000000000000000007fffdc6f043e4a69ea179a7a", 16); + StoredBlock block849137ToStore = new StoredBlock(block849137, block849137ChainWork, 849137); + + // save parent in storage + btcBlockStoreWithCache.put(block849137ToStore); + btcBlockStoreWithCache.setChainHead(block849137ToStore); + repository.save(); + // assert that parent was correctly saved + assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), block849137ToStore.getHeader().getHash()); // assert receive header returns an exception and does not save the block Integer RECEIVE_HEADER_UNEXPECTED_EXCEPTION = -99; - assertThat(bridgeSupport.receiveHeader(btcBlockWithTooMuchWork), is(RECEIVE_HEADER_UNEXPECTED_EXCEPTION)); - assertNull(btcBlockStoreWithCache.get(btcBlockWithTooMuchWork.getHash())); + assertThat(bridgeSupport.receiveHeader(blockWithTooMuchWork), is(RECEIVE_HEADER_UNEXPECTED_EXCEPTION)); + assertNull(btcBlockStoreWithCache.get(blockWithTooMuchWork.getHash())); } @Test - void receiveHeader_afterRSKIP434_returnsSuccessful() throws BlockStoreException, IOException { - // first assert that previous block was correctly saved - assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), previousBlock.getHash()); - + void receiveHeaders_beforeRSKIP434_savesBlocksUntilReachesBlockWithTooMuchChainWork() throws BlockStoreException, IOException { + activations = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP434).forBlock(0); + bridgeStorageProvider = new BridgeStorageProvider( + repository, + PrecompiledContracts.BRIDGE_ADDR, + bridgeMainnetConstants, + activations + ); bridgeSupport = bridgeSupportBuilder .withBridgeConstants(bridgeMainnetConstants) .withProvider(bridgeStorageProvider) @@ -6314,20 +6325,40 @@ void receiveHeader_afterRSKIP434_returnsSuccessful() throws BlockStoreException, .withBtcBlockStoreFactory(btcBlockStoreFactory) .withActivations(activations) .build(); + btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); - // assert receive header returns successful response and saves the block - Integer RECEIVE_HEADER_SUCCESSFUL = 0; - assertThat(bridgeSupport.receiveHeader(btcBlockWithTooMuchWork), is(RECEIVE_HEADER_SUCCESSFUL)); - assertNotNull(btcBlockStoreWithCache.get(btcBlockWithTooMuchWork.getHash())); + // Create block 849134 with cumulative difficulty + BigInteger block849134ChainWork = new BigInteger("00000000000000000000000000000000000000007ffef81fa11393037c9df17b", 16); + StoredBlock block849134ToStore = new StoredBlock(block849134, block849134ChainWork, 849134); + + // save block 849134 in storage + btcBlockStoreWithCache.put(block849134ToStore); + btcBlockStoreWithCache.setChainHead(block849134ToStore); + repository.save(); + // assert that block 849134 was correctly saved + assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), block849134.getHash()); + + BtcBlock[] headersToSend = new BtcBlock[] { block849135, block849136, block849137, blockWithTooMuchWork, block849139 }; + // assert blocks until 849137 are correctly saved + // and blocks from 849138 are not saved + bridgeSupport.receiveHeaders(headersToSend); + assertNotNull(btcBlockStoreWithCache.get(block849135.getHash())); + assertNotNull(btcBlockStoreWithCache.get(block849136.getHash())); + assertNotNull(btcBlockStoreWithCache.get(block849137.getHash())); + assertNull(btcBlockStoreWithCache.get(blockWithTooMuchWork.getHash())); + assertNull(btcBlockStoreWithCache.get(block849139.getHash())); } @Test - void receiveHeaders_beforeRSKIP434_catchesTheException() throws BlockStoreException, IOException { - activations = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP434).forBlock(0); - - // first assert that previous block was correctly saved - assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), previousBlock.getHash()); - + void receiveHeader_afterRSKIP434_returnsSuccessfulAndSavesTheBlock() throws BlockStoreException, IOException { + // rskip434 should be active + activations = ActivationConfigsForTest.all().forBlock(0); + bridgeStorageProvider = new BridgeStorageProvider( + repository, + PrecompiledContracts.BRIDGE_ADDR, + bridgeMainnetConstants, + activations + ); bridgeSupport = bridgeSupportBuilder .withBridgeConstants(bridgeMainnetConstants) .withProvider(bridgeStorageProvider) @@ -6335,17 +6366,34 @@ void receiveHeaders_beforeRSKIP434_catchesTheException() throws BlockStoreExcept .withBtcBlockStoreFactory(btcBlockStoreFactory) .withActivations(activations) .build(); + btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); - // assert receive headers does not save the block - bridgeSupport.receiveHeaders(new BtcBlock[] { btcBlockWithTooMuchWork }); - assertNull(btcBlockStoreWithCache.get(btcBlockWithTooMuchWork.getHash())); + // Create block with too much work parent with cumulative difficulty + BigInteger block849137ChainWork = new BigInteger("00000000000000000000000000000000000000007fffdc6f043e4a69ea179a7a", 16); + StoredBlock block849137ToStore = new StoredBlock(block849137, block849137ChainWork, 849137); + + // save parent in storage + btcBlockStoreWithCache.put(block849137ToStore); + btcBlockStoreWithCache.setChainHead(block849137ToStore); + repository.save(); + // assert that previous block was correctly saved + assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), block849137ToStore.getHeader().getHash()); + + // assert receive header returns successful response and saves the block + Integer RECEIVE_HEADER_SUCCESSFUL = 0; + assertThat(bridgeSupport.receiveHeader(blockWithTooMuchWork), is(RECEIVE_HEADER_SUCCESSFUL)); + assertNotNull(btcBlockStoreWithCache.get(blockWithTooMuchWork.getHash())); } @Test - void receiveHeaders_afterRSKIP434_savesTheBlock() throws BlockStoreException, IOException { - // first assert that previous block was correctly saved - assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), previousBlock.getHash()); - + void receiveHeaders_afterRSKIP434_savesAllBlocks() throws BlockStoreException, IOException { + activations = ActivationConfigsForTest.all().forBlock(0); + bridgeStorageProvider = new BridgeStorageProvider( + repository, + PrecompiledContracts.BRIDGE_ADDR, + bridgeMainnetConstants, + activations + ); bridgeSupport = bridgeSupportBuilder .withBridgeConstants(bridgeMainnetConstants) .withProvider(bridgeStorageProvider) @@ -6353,10 +6401,27 @@ void receiveHeaders_afterRSKIP434_savesTheBlock() throws BlockStoreException, IO .withBtcBlockStoreFactory(btcBlockStoreFactory) .withActivations(activations) .build(); + btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); - // assert block was correctly saved - bridgeSupport.receiveHeaders(new BtcBlock[] { btcBlockWithTooMuchWork }); - assertNotNull(btcBlockStoreWithCache.get(btcBlockWithTooMuchWork.getHash())); + // Create block 849134 with cumulative difficulty + BigInteger block849134ChainWork = new BigInteger("00000000000000000000000000000000000000007ffef81fa11393037c9df17b", 16); + StoredBlock block849134ToStore = new StoredBlock(block849134, block849134ChainWork, 849134); + + // save block 849134 in storage + btcBlockStoreWithCache.put(block849134ToStore); + btcBlockStoreWithCache.setChainHead(block849134ToStore); + repository.save(); + // assert that block 849134 was correctly saved + assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), block849134.getHash()); + + BtcBlock[] headersToSend = new BtcBlock[] { block849135, block849136, block849137, blockWithTooMuchWork, block849139 }; + // assert all blocks are correctly saved + bridgeSupport.receiveHeaders(headersToSend); + assertNotNull(btcBlockStoreWithCache.get(block849135.getHash())); + assertNotNull(btcBlockStoreWithCache.get(block849136.getHash())); + assertNotNull(btcBlockStoreWithCache.get(block849137.getHash())); + assertNotNull(btcBlockStoreWithCache.get(blockWithTooMuchWork.getHash())); + assertNotNull(btcBlockStoreWithCache.get(block849139.getHash())); } } From e188c2c4128b7bddbbb805955d8db2bd184a3dcc Mon Sep 17 00:00:00 2001 From: julia-zack Date: Mon, 1 Jul 2024 09:43:34 -0300 Subject: [PATCH 07/20] Add tests for regtest and mainnet --- .../java/co/rsk/peg/BridgeSupportTest.java | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java index b20d0b38c46..b065324bf7a 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java @@ -6423,6 +6423,95 @@ void receiveHeaders_afterRSKIP434_savesAllBlocks() throws BlockStoreException, I assertNotNull(btcBlockStoreWithCache.get(blockWithTooMuchWork.getHash())); assertNotNull(btcBlockStoreWithCache.get(block849139.getHash())); } + + @ParameterizedTest + @MethodSource("notMainnetAndActivationsArgs") + void receiveHeader_networkNotMainnet_returnsSuccessfulAndSavesTheBlock(ActivationConfig.ForBlock activations, BridgeConstants bridgeConstants) throws BlockStoreException, IOException { + bridgeStorageProvider = new BridgeStorageProvider( + repository, + PrecompiledContracts.BRIDGE_ADDR, + bridgeConstants, + activations + ); + bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstants) + .withProvider(bridgeStorageProvider) + .withRepository(repository) + .withBtcBlockStoreFactory(btcBlockStoreFactory) + .withActivations(activations) + .build(); + btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeConstants, bridgeStorageProvider, activations); + + // Create block with too much work parent with cumulative difficulty + BigInteger block849137ChainWork = new BigInteger("00000000000000000000000000000000000000007fffdc6f043e4a69ea179a7a", 16); + StoredBlock block849137ToStore = new StoredBlock(block849137, block849137ChainWork, 849137); + + // save parent in storage + btcBlockStoreWithCache.put(block849137ToStore); + btcBlockStoreWithCache.setChainHead(block849137ToStore); + repository.save(); + // assert that previous block was correctly saved + assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), block849137ToStore.getHeader().getHash()); + + // assert receive header returns successful response and saves the block + Integer RECEIVE_HEADER_SUCCESSFUL = 0; + assertThat(bridgeSupport.receiveHeader(blockWithTooMuchWork), is(RECEIVE_HEADER_SUCCESSFUL)); + assertNotNull(btcBlockStoreWithCache.get(blockWithTooMuchWork.getHash())); + } + + @ParameterizedTest + @MethodSource("notMainnetAndActivationsArgs") + void receiveHeaders_networkNotMainnet_savesAllBlocks(ActivationConfig.ForBlock activations, BridgeConstants bridgeConstants) throws BlockStoreException, IOException { + bridgeStorageProvider = new BridgeStorageProvider( + repository, + PrecompiledContracts.BRIDGE_ADDR, + bridgeConstants, + activations + ); + bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstants) + .withProvider(bridgeStorageProvider) + .withRepository(repository) + .withBtcBlockStoreFactory(btcBlockStoreFactory) + .withActivations(activations) + .build(); + btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeConstants, bridgeStorageProvider, activations); + + // Create block 849134 with cumulative difficulty + BigInteger block849134ChainWork = new BigInteger("00000000000000000000000000000000000000007ffef81fa11393037c9df17b", 16); + StoredBlock block849134ToStore = new StoredBlock(block849134, block849134ChainWork, 849134); + + // save block 849134 in storage + btcBlockStoreWithCache.put(block849134ToStore); + btcBlockStoreWithCache.setChainHead(block849134ToStore); + repository.save(); + // assert that block 849134 was correctly saved + assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), block849134.getHash()); + + BtcBlock[] headersToSend = new BtcBlock[] { block849135, block849136, block849137, blockWithTooMuchWork, block849139 }; + // assert all blocks are correctly saved + bridgeSupport.receiveHeaders(headersToSend); + assertNotNull(btcBlockStoreWithCache.get(block849135.getHash())); + assertNotNull(btcBlockStoreWithCache.get(block849136.getHash())); + assertNotNull(btcBlockStoreWithCache.get(block849137.getHash())); + assertNotNull(btcBlockStoreWithCache.get(blockWithTooMuchWork.getHash())); + assertNotNull(btcBlockStoreWithCache.get(block849139.getHash())); + } + + private Stream notMainnetAndActivationsArgs() { + ActivationConfig.ForBlock activationsPreRSKIP434 = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP434).forBlock(0); + ActivationConfig.ForBlock activationsPostRSKIP434 = ActivationConfigsForTest.all().forBlock(0); + + BridgeConstants testnet = BridgeTestNetConstants.getInstance(); + BridgeConstants regtest = BridgeRegTestConstants.getInstance(); + + return Stream.of( + Arguments.of(activationsPreRSKIP434, testnet), + Arguments.of(activationsPostRSKIP434, testnet), + Arguments.of(activationsPreRSKIP434, regtest), + Arguments.of(activationsPostRSKIP434, regtest) + ); + } } private void assertRefundInProcessPegInVersionLegacy( From 7c060c161b9e6d159f4de99622e00606434bccae Mon Sep 17 00:00:00 2001 From: Marcos Date: Wed, 3 Jul 2024 18:52:14 -0300 Subject: [PATCH 08/20] Set bitcoinj-thin dependency version to 0.14.4-rsk-15-SNAPSHOT --- rskj-core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rskj-core/build.gradle b/rskj-core/build.gradle index c103199df45..c0dfd7a6a2b 100644 --- a/rskj-core/build.gradle +++ b/rskj-core/build.gradle @@ -123,7 +123,7 @@ ext { jaxwsRtVer : '2.3.5', picocliVer : '4.6.3', - bitcoinjThinVer: '0.14.4-rsk-14', + bitcoinjThinVer: '0.14.4-rsk-15-SNAPSHOT', rskjNativeVer: '1.3.0', ] From d4e828d40af42b8320a6638b67e52330a17448ca Mon Sep 17 00:00:00 2001 From: julia-zack Date: Thu, 4 Jul 2024 11:16:14 -0300 Subject: [PATCH 09/20] Fix BridgeSupportTestIntegration broken test --- .../rsk/peg/BridgeSupportTestIntegration.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestIntegration.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestIntegration.java index de8c31376b9..50b7b0d6465 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestIntegration.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestIntegration.java @@ -938,10 +938,29 @@ void addBlockHeaderToBlockchain() throws IOException, BlockStoreException { BridgeSupport bridgeSupport = getBridgeSupport(provider, track, mockFactory, activations); BtcBlockChain btcBlockChain = new SimpleBlockChain(btcContext, btcBlockStore); TestUtils.setInternalState(bridgeSupport, "btcBlockChain", btcBlockChain); + + Sha256Hash merkleRoot = PegTestUtils.createHash(2); + + co.rsk.bitcoinj.core.BtcBlock prevBlock = new co.rsk.bitcoinj.core.BtcBlock( + btcParams, + 1, + PegTestUtils.createHash(1), // hash from its previous block + merkleRoot, + 1, + 1, + 1, + new ArrayList<>() + ); + BigInteger prevBlockChainWork = new BigInteger("ffffffffffffffff", 16); + StoredBlock prevStoredBlock = new StoredBlock(prevBlock, prevBlockChainWork, 1); + // save previous block in storage, so we are able to build next block from it + btcBlockStore.put(prevStoredBlock); + track.save(); + co.rsk.bitcoinj.core.BtcBlock block = new co.rsk.bitcoinj.core.BtcBlock( btcParams, 1, - PegTestUtils.createHash(1), + prevBlock.getHash(), PegTestUtils.createHash(2), 1, 1, From 8617deac156738bdbc4385c4fe65bd7ed7514620 Mon Sep 17 00:00:00 2001 From: julia-zack Date: Thu, 4 Jul 2024 11:17:55 -0300 Subject: [PATCH 10/20] Refactor chain work tests to reuse setup when possible --- .../java/co/rsk/peg/BridgeSupportTest.java | 185 ++++++++---------- 1 file changed, 79 insertions(+), 106 deletions(-) diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java index b065324bf7a..3d9edd65b04 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java @@ -6232,14 +6232,16 @@ void receiveHeader_block_exist_in_storage() throws IOException, BlockStoreExcept @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Tag("test chain work before and after rskip 434") class ChainWorkTests { - ActivationConfig.ForBlock activations; - BridgeConstants bridgeMainnetConstants = BridgeMainNetConstants.getInstance(); Repository repository; - BridgeStorageProvider bridgeStorageProvider; BtcBlockStoreWithCache.Factory btcBlockStoreFactory; - BtcBlockStoreWithCache btcBlockStoreWithCache; + BridgeStorageProvider bridgeStorageProviderPreRSKIP434; + BridgeStorageProvider bridgeStorageProviderPostRSKIP434; + BtcBlockStoreWithCache btcBlockStoreWithCachePreRSKIP434; + BtcBlockStoreWithCache btcBlockStoreWithCachePostRSKIP434; + BridgeSupportBuilder bridgeSupportBuilder = new BridgeSupportBuilder(); - BridgeSupport bridgeSupport; + BridgeSupport bridgeSupportPreRSKIP434; + BridgeSupport bridgeSupportPostRSKIP434; BtcBlock block849134; BtcBlock block849135; @@ -6250,10 +6252,47 @@ class ChainWorkTests { @BeforeEach void setUp() { - activations = ActivationConfigsForTest.all().forBlock(0); + BridgeConstants bridgeMainnetConstants = BridgeMainNetConstants.getInstance(); + ActivationConfig.ForBlock activationsPreRSKIP434 = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP434).forBlock(0); + ActivationConfig.ForBlock activationsPostRSKIP434 = ActivationConfigsForTest.all().forBlock(0); + repository = createRepository(); btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory(bridgeMainnetConstants.getBtcParams(), 100, 100); + // recreate context pre rskip 434 for mainnet + bridgeStorageProviderPreRSKIP434 = new BridgeStorageProvider( + repository, + PrecompiledContracts.BRIDGE_ADDR, + bridgeMainnetConstants, + activationsPreRSKIP434 + ); + bridgeSupportPreRSKIP434 = bridgeSupportBuilder + .withBridgeConstants(bridgeMainnetConstants) + .withProvider(bridgeStorageProviderPreRSKIP434) + .withRepository(repository) + .withBtcBlockStoreFactory(btcBlockStoreFactory) + .withActivations(activationsPreRSKIP434) + .build(); + btcBlockStoreWithCachePreRSKIP434 = + btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProviderPreRSKIP434, activationsPreRSKIP434); + + // recreate context post rskip 434 for mainnet + bridgeStorageProviderPostRSKIP434 = new BridgeStorageProvider( + repository, + PrecompiledContracts.BRIDGE_ADDR, + bridgeMainnetConstants, + activationsPostRSKIP434 + ); + bridgeSupportPostRSKIP434 = bridgeSupportBuilder + .withBridgeConstants(bridgeMainnetConstants) + .withProvider(bridgeStorageProviderPostRSKIP434) + .withRepository(repository) + .withBtcBlockStoreFactory(btcBlockStoreFactory) + .withActivations(activationsPostRSKIP434) + .build(); + btcBlockStoreWithCachePostRSKIP434 = + btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProviderPostRSKIP434, activationsPostRSKIP434); + String block849134Header = "0080b92c24f123130ae29e899f0cab72653722e54cdf3b30445202000000000000000000c72ead65a3b78ab637d1876c00414a77e47bcc5b52667ac1e573633563bea5a695aa7766255d031728d182a8"; block849134 = new BtcBlock(bridgeMainnetConstants.getBtcParams(), HexUtils.stringHexToByteArray(block849134Header)); @@ -6275,172 +6314,106 @@ void setUp() { @Test void receiveHeader_beforeRSKIP434_returnsUnexpectedExceptionResponseCodeAndDoesNotSaveTheBlock() throws BlockStoreException, IOException { - // rskip434 should be inactive - activations = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP434).forBlock(0); - bridgeStorageProvider = new BridgeStorageProvider( - repository, - PrecompiledContracts.BRIDGE_ADDR, - bridgeMainnetConstants, - activations - ); - bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeMainnetConstants) - .withProvider(bridgeStorageProvider) - .withRepository(repository) - .withBtcBlockStoreFactory(btcBlockStoreFactory) - .withActivations(activations) - .build(); - btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); - // Create block with too much work parent with cumulative difficulty BigInteger block849137ChainWork = new BigInteger("00000000000000000000000000000000000000007fffdc6f043e4a69ea179a7a", 16); StoredBlock block849137ToStore = new StoredBlock(block849137, block849137ChainWork, 849137); // save parent in storage - btcBlockStoreWithCache.put(block849137ToStore); - btcBlockStoreWithCache.setChainHead(block849137ToStore); + btcBlockStoreWithCachePreRSKIP434.put(block849137ToStore); + btcBlockStoreWithCachePreRSKIP434.setChainHead(block849137ToStore); repository.save(); // assert that parent was correctly saved - assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), block849137ToStore.getHeader().getHash()); + assertEquals(btcBlockStoreWithCachePreRSKIP434.getChainHead().getHeader().getHash(), block849137ToStore.getHeader().getHash()); // assert receive header returns an exception and does not save the block Integer RECEIVE_HEADER_UNEXPECTED_EXCEPTION = -99; - assertThat(bridgeSupport.receiveHeader(blockWithTooMuchWork), is(RECEIVE_HEADER_UNEXPECTED_EXCEPTION)); - assertNull(btcBlockStoreWithCache.get(blockWithTooMuchWork.getHash())); + assertThat(bridgeSupportPreRSKIP434.receiveHeader(blockWithTooMuchWork), is(RECEIVE_HEADER_UNEXPECTED_EXCEPTION)); + assertNull(btcBlockStoreWithCachePreRSKIP434.get(blockWithTooMuchWork.getHash())); } @Test void receiveHeaders_beforeRSKIP434_savesBlocksUntilReachesBlockWithTooMuchChainWork() throws BlockStoreException, IOException { - activations = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP434).forBlock(0); - bridgeStorageProvider = new BridgeStorageProvider( - repository, - PrecompiledContracts.BRIDGE_ADDR, - bridgeMainnetConstants, - activations - ); - bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeMainnetConstants) - .withProvider(bridgeStorageProvider) - .withRepository(repository) - .withBtcBlockStoreFactory(btcBlockStoreFactory) - .withActivations(activations) - .build(); - btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); - // Create block 849134 with cumulative difficulty BigInteger block849134ChainWork = new BigInteger("00000000000000000000000000000000000000007ffef81fa11393037c9df17b", 16); StoredBlock block849134ToStore = new StoredBlock(block849134, block849134ChainWork, 849134); // save block 849134 in storage - btcBlockStoreWithCache.put(block849134ToStore); - btcBlockStoreWithCache.setChainHead(block849134ToStore); + btcBlockStoreWithCachePreRSKIP434.put(block849134ToStore); + btcBlockStoreWithCachePreRSKIP434.setChainHead(block849134ToStore); repository.save(); // assert that block 849134 was correctly saved - assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), block849134.getHash()); + assertEquals(btcBlockStoreWithCachePreRSKIP434.getChainHead().getHeader().getHash(), block849134.getHash()); BtcBlock[] headersToSend = new BtcBlock[] { block849135, block849136, block849137, blockWithTooMuchWork, block849139 }; // assert blocks until 849137 are correctly saved // and blocks from 849138 are not saved - bridgeSupport.receiveHeaders(headersToSend); - assertNotNull(btcBlockStoreWithCache.get(block849135.getHash())); - assertNotNull(btcBlockStoreWithCache.get(block849136.getHash())); - assertNotNull(btcBlockStoreWithCache.get(block849137.getHash())); - assertNull(btcBlockStoreWithCache.get(blockWithTooMuchWork.getHash())); - assertNull(btcBlockStoreWithCache.get(block849139.getHash())); + bridgeSupportPreRSKIP434.receiveHeaders(headersToSend); + assertNotNull(btcBlockStoreWithCachePreRSKIP434.get(block849135.getHash())); + assertNotNull(btcBlockStoreWithCachePreRSKIP434.get(block849136.getHash())); + assertNotNull(btcBlockStoreWithCachePreRSKIP434.get(block849137.getHash())); + assertNull(btcBlockStoreWithCachePreRSKIP434.get(blockWithTooMuchWork.getHash())); + assertNull(btcBlockStoreWithCachePreRSKIP434.get(block849139.getHash())); } @Test void receiveHeader_afterRSKIP434_returnsSuccessfulAndSavesTheBlock() throws BlockStoreException, IOException { - // rskip434 should be active - activations = ActivationConfigsForTest.all().forBlock(0); - bridgeStorageProvider = new BridgeStorageProvider( - repository, - PrecompiledContracts.BRIDGE_ADDR, - bridgeMainnetConstants, - activations - ); - bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeMainnetConstants) - .withProvider(bridgeStorageProvider) - .withRepository(repository) - .withBtcBlockStoreFactory(btcBlockStoreFactory) - .withActivations(activations) - .build(); - btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); - // Create block with too much work parent with cumulative difficulty BigInteger block849137ChainWork = new BigInteger("00000000000000000000000000000000000000007fffdc6f043e4a69ea179a7a", 16); StoredBlock block849137ToStore = new StoredBlock(block849137, block849137ChainWork, 849137); // save parent in storage - btcBlockStoreWithCache.put(block849137ToStore); - btcBlockStoreWithCache.setChainHead(block849137ToStore); + btcBlockStoreWithCachePostRSKIP434.put(block849137ToStore); + btcBlockStoreWithCachePostRSKIP434.setChainHead(block849137ToStore); repository.save(); // assert that previous block was correctly saved - assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), block849137ToStore.getHeader().getHash()); + assertEquals(btcBlockStoreWithCachePostRSKIP434.getChainHead().getHeader().getHash(), block849137ToStore.getHeader().getHash()); // assert receive header returns successful response and saves the block Integer RECEIVE_HEADER_SUCCESSFUL = 0; - assertThat(bridgeSupport.receiveHeader(blockWithTooMuchWork), is(RECEIVE_HEADER_SUCCESSFUL)); - assertNotNull(btcBlockStoreWithCache.get(blockWithTooMuchWork.getHash())); + assertThat(bridgeSupportPostRSKIP434.receiveHeader(blockWithTooMuchWork), is(RECEIVE_HEADER_SUCCESSFUL)); + assertNotNull(btcBlockStoreWithCachePostRSKIP434.get(blockWithTooMuchWork.getHash())); } @Test void receiveHeaders_afterRSKIP434_savesAllBlocks() throws BlockStoreException, IOException { - activations = ActivationConfigsForTest.all().forBlock(0); - bridgeStorageProvider = new BridgeStorageProvider( - repository, - PrecompiledContracts.BRIDGE_ADDR, - bridgeMainnetConstants, - activations - ); - bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(bridgeMainnetConstants) - .withProvider(bridgeStorageProvider) - .withRepository(repository) - .withBtcBlockStoreFactory(btcBlockStoreFactory) - .withActivations(activations) - .build(); - btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProvider, activations); - // Create block 849134 with cumulative difficulty BigInteger block849134ChainWork = new BigInteger("00000000000000000000000000000000000000007ffef81fa11393037c9df17b", 16); StoredBlock block849134ToStore = new StoredBlock(block849134, block849134ChainWork, 849134); // save block 849134 in storage - btcBlockStoreWithCache.put(block849134ToStore); - btcBlockStoreWithCache.setChainHead(block849134ToStore); + btcBlockStoreWithCachePostRSKIP434.put(block849134ToStore); + btcBlockStoreWithCachePostRSKIP434.setChainHead(block849134ToStore); repository.save(); // assert that block 849134 was correctly saved - assertEquals(btcBlockStoreWithCache.getChainHead().getHeader().getHash(), block849134.getHash()); + assertEquals(btcBlockStoreWithCachePostRSKIP434.getChainHead().getHeader().getHash(), block849134.getHash()); BtcBlock[] headersToSend = new BtcBlock[] { block849135, block849136, block849137, blockWithTooMuchWork, block849139 }; // assert all blocks are correctly saved - bridgeSupport.receiveHeaders(headersToSend); - assertNotNull(btcBlockStoreWithCache.get(block849135.getHash())); - assertNotNull(btcBlockStoreWithCache.get(block849136.getHash())); - assertNotNull(btcBlockStoreWithCache.get(block849137.getHash())); - assertNotNull(btcBlockStoreWithCache.get(blockWithTooMuchWork.getHash())); - assertNotNull(btcBlockStoreWithCache.get(block849139.getHash())); + bridgeSupportPostRSKIP434.receiveHeaders(headersToSend); + assertNotNull(btcBlockStoreWithCachePostRSKIP434.get(block849135.getHash())); + assertNotNull(btcBlockStoreWithCachePostRSKIP434.get(block849136.getHash())); + assertNotNull(btcBlockStoreWithCachePostRSKIP434.get(block849137.getHash())); + assertNotNull(btcBlockStoreWithCachePostRSKIP434.get(blockWithTooMuchWork.getHash())); + assertNotNull(btcBlockStoreWithCachePostRSKIP434.get(block849139.getHash())); } @ParameterizedTest @MethodSource("notMainnetAndActivationsArgs") void receiveHeader_networkNotMainnet_returnsSuccessfulAndSavesTheBlock(ActivationConfig.ForBlock activations, BridgeConstants bridgeConstants) throws BlockStoreException, IOException { - bridgeStorageProvider = new BridgeStorageProvider( + BridgeStorageProvider bridgeStorageProvider = new BridgeStorageProvider( repository, PrecompiledContracts.BRIDGE_ADDR, bridgeConstants, activations ); - bridgeSupport = bridgeSupportBuilder + BridgeSupport bridgeSupport = bridgeSupportBuilder .withBridgeConstants(bridgeConstants) .withProvider(bridgeStorageProvider) .withRepository(repository) .withBtcBlockStoreFactory(btcBlockStoreFactory) .withActivations(activations) .build(); - btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeConstants, bridgeStorageProvider, activations); + BtcBlockStoreWithCache btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeConstants, bridgeStorageProvider, activations); // Create block with too much work parent with cumulative difficulty BigInteger block849137ChainWork = new BigInteger("00000000000000000000000000000000000000007fffdc6f043e4a69ea179a7a", 16); @@ -6462,20 +6435,20 @@ void receiveHeader_networkNotMainnet_returnsSuccessfulAndSavesTheBlock(Activatio @ParameterizedTest @MethodSource("notMainnetAndActivationsArgs") void receiveHeaders_networkNotMainnet_savesAllBlocks(ActivationConfig.ForBlock activations, BridgeConstants bridgeConstants) throws BlockStoreException, IOException { - bridgeStorageProvider = new BridgeStorageProvider( + BridgeStorageProvider bridgeStorageProvider = new BridgeStorageProvider( repository, PrecompiledContracts.BRIDGE_ADDR, bridgeConstants, activations ); - bridgeSupport = bridgeSupportBuilder + BridgeSupport bridgeSupport = bridgeSupportBuilder .withBridgeConstants(bridgeConstants) .withProvider(bridgeStorageProvider) .withRepository(repository) .withBtcBlockStoreFactory(btcBlockStoreFactory) .withActivations(activations) .build(); - btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeConstants, bridgeStorageProvider, activations); + BtcBlockStoreWithCache btcBlockStoreWithCache = btcBlockStoreFactory.newInstance(repository, bridgeConstants, bridgeStorageProvider, activations); // Create block 849134 with cumulative difficulty BigInteger block849134ChainWork = new BigInteger("00000000000000000000000000000000000000007ffef81fa11393037c9df17b", 16); From bab0a24530ea47a97a0ef5c9bb7fadd35ef84693 Mon Sep 17 00:00:00 2001 From: julia-zack Date: Thu, 4 Jul 2024 11:21:18 -0300 Subject: [PATCH 11/20] Minor refactor --- rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java index 3d9edd65b04..e84712227f9 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java @@ -6234,8 +6234,6 @@ void receiveHeader_block_exist_in_storage() throws IOException, BlockStoreExcept class ChainWorkTests { Repository repository; BtcBlockStoreWithCache.Factory btcBlockStoreFactory; - BridgeStorageProvider bridgeStorageProviderPreRSKIP434; - BridgeStorageProvider bridgeStorageProviderPostRSKIP434; BtcBlockStoreWithCache btcBlockStoreWithCachePreRSKIP434; BtcBlockStoreWithCache btcBlockStoreWithCachePostRSKIP434; @@ -6260,7 +6258,7 @@ void setUp() { btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory(bridgeMainnetConstants.getBtcParams(), 100, 100); // recreate context pre rskip 434 for mainnet - bridgeStorageProviderPreRSKIP434 = new BridgeStorageProvider( + BridgeStorageProvider bridgeStorageProviderPreRSKIP434 = new BridgeStorageProvider( repository, PrecompiledContracts.BRIDGE_ADDR, bridgeMainnetConstants, @@ -6277,7 +6275,7 @@ void setUp() { btcBlockStoreFactory.newInstance(repository, bridgeMainnetConstants, bridgeStorageProviderPreRSKIP434, activationsPreRSKIP434); // recreate context post rskip 434 for mainnet - bridgeStorageProviderPostRSKIP434 = new BridgeStorageProvider( + BridgeStorageProvider bridgeStorageProviderPostRSKIP434 = new BridgeStorageProvider( repository, PrecompiledContracts.BRIDGE_ADDR, bridgeMainnetConstants, From 7c4cfb6bebb838816d1ed80bd1e3f61a79ec4440 Mon Sep 17 00:00:00 2001 From: julia-zack Date: Thu, 4 Jul 2024 13:25:06 -0300 Subject: [PATCH 12/20] Add arrowhead631 config. Adapt tests --- .../blockchain/upgrades/NetworkUpgrade.java | 1 + rskj-core/src/main/resources/config/main.conf | 4 +-- .../src/main/resources/config/regtest.conf | 4 +-- .../src/main/resources/config/testnet.conf | 4 +-- rskj-core/src/main/resources/expected.conf | 2 ++ rskj-core/src/main/resources/reference.conf | 1 + .../java/co/rsk/peg/BridgeSupportTest.java | 18 ++++------ .../upgrades/ActivationConfigTest.java | 2 ++ .../upgrades/ActivationConfigsForTest.java | 33 +++++++++++++++++++ 9 files changed, 51 insertions(+), 18 deletions(-) diff --git a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/NetworkUpgrade.java b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/NetworkUpgrade.java index e47ed0fe7d6..36670f845e0 100644 --- a/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/NetworkUpgrade.java +++ b/rskj-core/src/main/java/org/ethereum/config/blockchain/upgrades/NetworkUpgrade.java @@ -32,6 +32,7 @@ public enum NetworkUpgrade { HOP401("hop401"), FINGERROOT500("fingerroot500"), ARROWHEAD600("arrowhead600"), + ARROWHEAD631("arrowhead631"), LOVELL700("lovell700"); private String name; diff --git a/rskj-core/src/main/resources/config/main.conf b/rskj-core/src/main/resources/config/main.conf index 268a17ac80a..ccd00dbfe0c 100644 --- a/rskj-core/src/main/resources/config/main.conf +++ b/rskj-core/src/main/resources/config/main.conf @@ -13,10 +13,8 @@ blockchain.config { hop401 = 4976300, fingerroot500 = 5468000, arrowhead600 = 6223700, + arrowhead631 = -1, lovell700 = -1 - }, - consensusRules = { - rskip434 = -1 } } diff --git a/rskj-core/src/main/resources/config/regtest.conf b/rskj-core/src/main/resources/config/regtest.conf index 1d2a5cd86ee..d19ce575c34 100644 --- a/rskj-core/src/main/resources/config/regtest.conf +++ b/rskj-core/src/main/resources/config/regtest.conf @@ -13,12 +13,12 @@ blockchain.config { hop401 = 0, fingerroot500 = 0, arrowhead600 = 0, + arrowhead631 = -1, lovell700 = 0 }, consensusRules = { rskip97 = -1 # disable orchid difficulty drop - rskipUMM = 1, - rskip434 = -1 + rskipUMM = 1 } } diff --git a/rskj-core/src/main/resources/config/testnet.conf b/rskj-core/src/main/resources/config/testnet.conf index d6d4f8cf7a4..cfe42731cd8 100644 --- a/rskj-core/src/main/resources/config/testnet.conf +++ b/rskj-core/src/main/resources/config/testnet.conf @@ -13,14 +13,14 @@ blockchain.config { hop401 = 3362200, fingerroot500 = 4015800, arrowhead600 = 4927100, + arrowhead631 = -1, lovell700 = -1 }, consensusRules = { rskip97 = -1, # disable orchid difficulty drop rskip132 = 43550, # enable recalculted receive headers cost rskip284 = 2581800, - rskip290 = 2581800, - rskip434 = -1 + rskip290 = 2581800 } } diff --git a/rskj-core/src/main/resources/expected.conf b/rskj-core/src/main/resources/expected.conf index 77f384ff6b7..5b440a1367e 100644 --- a/rskj-core/src/main/resources/expected.conf +++ b/rskj-core/src/main/resources/expected.conf @@ -16,6 +16,7 @@ blockchain = { hop401 = fingerroot500 = arrowhead600 = + arrowhead631 = lovell700 = } consensusRules = { @@ -94,6 +95,7 @@ blockchain = { rskip415 = rskip417 = rskip428 = + rskip434 = } } gc = { diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index 2789bb1c7f1..8228aa620d1 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -80,6 +80,7 @@ blockchain = { rskip415 = arrowhead600 rskip417 = arrowhead600 rskip428 = lovell700 + rskip434 = arrowhead631 } } gc = { diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java index e84712227f9..8d1df5e85ea 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java @@ -6232,6 +6232,8 @@ void receiveHeader_block_exist_in_storage() throws IOException, BlockStoreExcept @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Tag("test chain work before and after rskip 434") class ChainWorkTests { + ActivationConfig.ForBlock activationsPreRSKIP434 = ActivationConfigsForTest.arrowhead631(Collections.singletonList(ConsensusRule.RSKIP434)).forBlock(0); + ActivationConfig.ForBlock activationsPostRSKIP434 = ActivationConfigsForTest.arrowhead631().forBlock(0); Repository repository; BtcBlockStoreWithCache.Factory btcBlockStoreFactory; BtcBlockStoreWithCache btcBlockStoreWithCachePreRSKIP434; @@ -6251,9 +6253,6 @@ class ChainWorkTests { @BeforeEach void setUp() { BridgeConstants bridgeMainnetConstants = BridgeMainNetConstants.getInstance(); - ActivationConfig.ForBlock activationsPreRSKIP434 = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP434).forBlock(0); - ActivationConfig.ForBlock activationsPostRSKIP434 = ActivationConfigsForTest.all().forBlock(0); - repository = createRepository(); btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory(bridgeMainnetConstants.getBtcParams(), 100, 100); @@ -6470,18 +6469,15 @@ void receiveHeaders_networkNotMainnet_savesAllBlocks(ActivationConfig.ForBlock a } private Stream notMainnetAndActivationsArgs() { - ActivationConfig.ForBlock activationsPreRSKIP434 = ActivationConfigsForTest.allBut(ConsensusRule.RSKIP434).forBlock(0); - ActivationConfig.ForBlock activationsPostRSKIP434 = ActivationConfigsForTest.all().forBlock(0); - BridgeConstants testnet = BridgeTestNetConstants.getInstance(); BridgeConstants regtest = BridgeRegTestConstants.getInstance(); return Stream.of( - Arguments.of(activationsPreRSKIP434, testnet), - Arguments.of(activationsPostRSKIP434, testnet), - Arguments.of(activationsPreRSKIP434, regtest), - Arguments.of(activationsPostRSKIP434, regtest) - ); + Arguments.of(activationsPreRSKIP434, testnet), + Arguments.of(activationsPostRSKIP434, testnet), + Arguments.of(activationsPreRSKIP434, regtest), + Arguments.of(activationsPostRSKIP434, regtest) + ); } } diff --git a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java index 00f4affaff2..0593855f481 100644 --- a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java +++ b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigTest.java @@ -43,6 +43,7 @@ class ActivationConfigTest { " hop401: 0", " fingerroot500: 0", " arrowhead600: 0", + " arrowhead631: 0", " lovell700: 0", "},", "consensusRules: {", @@ -120,6 +121,7 @@ class ActivationConfigTest { " rskip412: arrowhead600", " rskip415: arrowhead600", " rskip417: arrowhead600", + " rskip434: arrowhead631", " rskip428: lovell700", "}" )); diff --git a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigsForTest.java b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigsForTest.java index a1b080a2b57..dc85d0e61ed 100644 --- a/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigsForTest.java +++ b/rskj-core/src/test/java/org/ethereum/config/blockchain/upgrades/ActivationConfigsForTest.java @@ -191,6 +191,15 @@ private static List getArrowhead600Rskips() { return rskips; } + private static List getArrowhead631Rskips() { + List rskips = new ArrayList<>(); + rskips.addAll(Collections.singletonList( + ConsensusRule.RSKIP434 + )); + + return rskips; + } + private static List getLovell700Rskips() { List rskips = new ArrayList<>(); rskips.addAll(Arrays.asList( @@ -341,6 +350,29 @@ public static ActivationConfig arrowhead600(List except) { return enableTheseDisableThose(rskips, except); } + public static ActivationConfig arrowhead631() { + return arrowhead631(Collections.emptyList()); + } + + public static ActivationConfig arrowhead631(List except) { + List rskips = new ArrayList<>(); + rskips.addAll(getPaidBridgeTxsRskip()); + rskips.addAll(getOrchidRskips()); + rskips.addAll(getOrchid060Rskips()); + rskips.addAll(getWasabi100Rskips()); + rskips.addAll(getBahamasRskips()); + rskips.addAll(getTwoToThreeRskips()); + rskips.addAll(getPapyrus200Rskips()); + rskips.addAll(getIris300Rskips()); + rskips.addAll(getHop400Rskips()); + rskips.addAll(getHop401Rskips()); + rskips.addAll(getFingerroot500Rskips()); + rskips.addAll(getArrowhead600Rskips()); + rskips.addAll(getArrowhead631Rskips()); + + return enableTheseDisableThose(rskips, except); + } + public static ActivationConfig lovell700(List except) { List rskips = new ArrayList<>(); rskips.addAll(getPaidBridgeTxsRskip()); @@ -355,6 +387,7 @@ public static ActivationConfig lovell700(List except) { rskips.addAll(getHop401Rskips()); rskips.addAll(getFingerroot500Rskips()); rskips.addAll(getArrowhead600Rskips()); + rskips.addAll(getArrowhead631Rskips()); rskips.addAll(getLovell700Rskips()); return enableTheseDisableThose(rskips, except); From 59ebb2b7add07252ff3404d6ed85d04b0d294a45 Mon Sep 17 00:00:00 2001 From: julia-zack Date: Thu, 4 Jul 2024 13:27:29 -0300 Subject: [PATCH 13/20] Minor refactor --- rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java index 8d1df5e85ea..c63c0c185ee 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java @@ -6232,7 +6232,7 @@ void receiveHeader_block_exist_in_storage() throws IOException, BlockStoreExcept @TestInstance(TestInstance.Lifecycle.PER_CLASS) @Tag("test chain work before and after rskip 434") class ChainWorkTests { - ActivationConfig.ForBlock activationsPreRSKIP434 = ActivationConfigsForTest.arrowhead631(Collections.singletonList(ConsensusRule.RSKIP434)).forBlock(0); + ActivationConfig.ForBlock activationsPreRSKIP434 = ActivationConfigsForTest.arrowhead600().forBlock(0); ActivationConfig.ForBlock activationsPostRSKIP434 = ActivationConfigsForTest.arrowhead631().forBlock(0); Repository repository; BtcBlockStoreWithCache.Factory btcBlockStoreFactory; From 7f20b2bfe62e4b7094d06b8e04d39c075ccca731 Mon Sep 17 00:00:00 2001 From: Marcos Date: Mon, 8 Jul 2024 14:25:03 -0300 Subject: [PATCH 14/20] Set bitcoinj-thin dependency version to 0.14.4-rsk-15 --- gradle/verification-metadata.xml | 10 +++++----- rskj-core/build.gradle | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 04c935a80ae..0cf43352580 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -46,12 +46,12 @@ - - - + + + - - + + diff --git a/rskj-core/build.gradle b/rskj-core/build.gradle index c0dfd7a6a2b..ff9496bf1b3 100644 --- a/rskj-core/build.gradle +++ b/rskj-core/build.gradle @@ -123,7 +123,7 @@ ext { jaxwsRtVer : '2.3.5', picocliVer : '4.6.3', - bitcoinjThinVer: '0.14.4-rsk-15-SNAPSHOT', + bitcoinjThinVer: '0.14.4-rsk-15', rskjNativeVer: '1.3.0', ] From dd6ddfd5077863c55fb8add86aa4555747042aa4 Mon Sep 17 00:00:00 2001 From: Marcos Date: Mon, 8 Jul 2024 14:27:03 -0300 Subject: [PATCH 15/20] Set activation height for Arrowhead-6.3.1 in mainnet --- rskj-core/src/main/resources/config/main.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rskj-core/src/main/resources/config/main.conf b/rskj-core/src/main/resources/config/main.conf index ccd00dbfe0c..da37b9165e1 100644 --- a/rskj-core/src/main/resources/config/main.conf +++ b/rskj-core/src/main/resources/config/main.conf @@ -13,7 +13,7 @@ blockchain.config { hop401 = 4976300, fingerroot500 = 5468000, arrowhead600 = 6223700, - arrowhead631 = -1, + arrowhead631 = 6549300, lovell700 = -1 } } From 5f9158ad4cf90e37dbf24f30369f89f436fd101b Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Mon, 1 Jul 2024 15:33:25 +0300 Subject: [PATCH 16/20] chore(logging): refactor and improve logging --- .../co/rsk/core/types/bytes/ByteSequence.java | 49 ++++++ .../java/co/rsk/core/types/bytes/Bytes.java | 157 ++++++++++++++++++ .../co/rsk/core/types/bytes/BytesSlice.java | 123 ++++++++++++++ .../core/types/bytes/HexPrintableBytes.java | 92 ++++++++++ .../rsk/core/types/bytes/PrintableBytes.java | 35 ++++ .../co/rsk/net/discovery/PacketDecoder.java | 4 +- .../message/PeerDiscoveryMessage.java | 9 +- .../co/rsk/net/handler/quota/TxQuota.java | 8 +- .../main/java/co/rsk/pcc/NativeContract.java | 10 +- .../rsk/pcc/bto/DeriveExtendedPublicKey.java | 5 +- ...ExtractPublicKeyFromExtendedPublicKey.java | 7 +- .../co/rsk/pcc/bto/GetMultisigScriptHash.java | 4 +- .../co/rsk/pcc/bto/HDWalletUtilsHelper.java | 3 +- .../java/co/rsk/pcc/bto/ToBase58Check.java | 6 +- .../src/main/java/co/rsk/peg/Bridge.java | 17 +- .../main/java/co/rsk/peg/BridgeSupport.java | 19 ++- .../java/co/rsk/peg/bitcoin/UtxoUtils.java | 4 +- .../rsk/peg/federation/FederationMember.java | 3 +- .../PeginInstructionsProvider.java | 4 +- .../java/co/rsk/remasc/RemascContract.java | 6 +- .../main/java/co/rsk/util/StringUtils.java | 40 +++++ .../validators/BlockRootValidationRule.java | 4 +- .../BlockUnclesHashValidationRule.java | 3 +- .../main/java/org/ethereum/core/Block.java | 4 +- .../org/ethereum/core/BlockIdentifier.java | 4 +- .../main/java/org/ethereum/core/Bloom.java | 3 +- .../org/ethereum/core/TransactionReceipt.java | 5 +- .../core/genesis/BlockChainLoader.java | 4 +- .../datasource/LevelDbDataSource.java | 15 +- .../datasource/RocksDbDataSource.java | 13 +- .../org/ethereum/db/ByteArrayWrapper.java | 3 +- .../net/eth/message/StatusMessage.java | 7 +- .../net/rlpx/AuthInitiateMessage.java | 10 +- .../net/rlpx/AuthInitiateMessageV4.java | 7 +- .../net/rlpx/AuthResponseMessage.java | 4 +- .../net/rlpx/AuthResponseMessageV4.java | 3 +- .../org/ethereum/net/rlpx/MessageCodec.java | 7 +- .../ethereum/net/server/PeerServerImpl.java | 6 +- .../src/main/java/org/ethereum/rpc/Topic.java | 9 +- .../org/ethereum/solidity/SolidityType.java | 3 +- .../src/main/java/org/ethereum/vm/VM.java | 5 +- .../java/org/ethereum/vm/program/Program.java | 3 +- .../invoke/ProgramInvokeFactoryImpl.java | 27 +-- ...actPublicKeyFromExtendedPublicKeyTest.java | 6 +- .../rsk/pcc/bto/HDWalletUtilsHelperTest.java | 21 ++- .../src/test/java/co/rsk/util/BytesTest.java | 76 +++++++++ .../java/org/ethereum/core/BloomTest.java | 8 +- 47 files changed, 737 insertions(+), 128 deletions(-) create mode 100644 rskj-core/src/main/java/co/rsk/core/types/bytes/ByteSequence.java create mode 100644 rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java create mode 100644 rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java create mode 100644 rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java create mode 100644 rskj-core/src/main/java/co/rsk/core/types/bytes/PrintableBytes.java create mode 100644 rskj-core/src/main/java/co/rsk/util/StringUtils.java create mode 100644 rskj-core/src/test/java/co/rsk/util/BytesTest.java diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/ByteSequence.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/ByteSequence.java new file mode 100644 index 00000000000..a771bbd200c --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/ByteSequence.java @@ -0,0 +1,49 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.core.types.bytes; + +/** + * {@link ByteSequence} is the most basic interface that represents read-only sequence of byte values. + */ +public interface ByteSequence { + + /** + * Returns the length of this byte sequence. + * + * @return the length of the sequence of bytes represented by this + * object. + */ + int length(); + + /** + * Returns the {@code byte} value at the + * specified index. An index ranges from {@code 0} to + * {@code length() - 1}. The first {@code byte} value of the sequence + * is at index {@code 0}, the next at index {@code 1}, + * and so on, as for array indexing. + * + * @param index the index of the {@code byte} value. + * @return the {@code byte} value at the specified index of this array. + * The first {@code byte} value is at index {@code 0}. + * @exception IndexOutOfBoundsException if the {@code index} + * argument is negative or not less than the length of this + * array. + */ + byte byteAt(int index); +} diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java new file mode 100644 index 00000000000..dd29eb55ee5 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java @@ -0,0 +1,157 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.core.types.bytes; + +import org.ethereum.util.ByteUtil; +import org.ethereum.util.FastByteComparisons; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Objects; + +/** + * A {@link Bytes} is a readable sequence of byte values. This + * interface provides uniform, read-only access to many different kinds of + * byte sequences. + * + *

This interface does not refine the general contracts of the {@link + * java.lang.Object#equals(java.lang.Object) equals} and {@link + * java.lang.Object#hashCode() hashCode} methods. The result of comparing two + * objects that implement Bytes is therefore, in general, + * undefined. Each object may be implemented by a different class, and there + * is no guarantee that each class will be capable of testing its instances + * for equality with those of the other. It is therefore inappropriate to use + * arbitrary Bytes instances as elements in a set or as keys in + * a map.

+ */ +public interface Bytes extends BytesSlice { + + /** + * Returns an instance of the {@link Bytes} interface, which represents {@code unsafeByteArray}. + * + * @return the instance of the {@link Bytes} interface that wraps a provided byte array. + */ + static Bytes of(@Nullable byte[] unsafeByteArray) { + if (unsafeByteArray == null) { + return null; + } + return new BytesImpl(unsafeByteArray); + } + + /** + * A helper method for printing "nullable" byte arrays. + * + * @return {@code null}, if {@code byteArray} is {@code null}. Otherwise - {@code Bytes.of(byteArray).toPrintableString()}. + */ + static String toPrintableString(@Nullable byte[] byteArray) { + if (byteArray == null) { + return null; + } + return of(byteArray).toPrintableString(); + } + + /** + * A helper method for extracting "unsafe" underlying byte array from the {@code bytes} instance. + * + * @return {@code null}, if {@code bytes} is {@code null}. Otherwise - {@code bytes.asUnsafeByteArray()}. + */ + @Nullable + static byte[] asUnsafeByteArray(@Nullable Bytes bytes) { + if (bytes == null) { + return null; + } + return bytes.asUnsafeByteArray(); + } + + static boolean equalBytes(Bytes b1, Bytes b2) { + if (b1 == null && b2 == null) { + return true; + } + if (b1 == null || b2 == null) { + return false; + } + return FastByteComparisons.equalBytes(b1.asUnsafeByteArray(), b2.asUnsafeByteArray()); + } + + /** + * Returns an underlying byte array, which is backing this instance. Any mutations that are being done with the bytes + * of returned array will have direct impact on the byte array that is being wrapped by this instance. + * + * @return the wrapped by this instance byte array. + */ + byte[] asUnsafeByteArray(); +} + +/** + * The {@link BytesImpl} class represents a read-only sequence of byte values. + *

+ * Instances of the {@link BytesImpl} class are constant; their values cannot be changed after they + * are created via the methods that this class provides. But a {@code byteArray} instance itself provided in the constructor + * is mutable and can be modified outside the class. It's generally a bad idea to mutate a byte array that's being wrapped + * by an instance of this class, as the idea is to make a byte sequence immutable, which is not the case with the Java + * built-in {@code byte[]} type. + *

+ * Because {@link BytesImpl} objects are immutable they can be safely used by multiple Java threads, if the wrapped array + * is not being referenced and modified outside. + */ +class BytesImpl implements Bytes { + + private final byte[] byteArray; + + BytesImpl(@Nonnull byte[] unsafeByteArray) { + this.byteArray = Objects.requireNonNull(unsafeByteArray); + } + + @Override + public int length() { + return byteArray.length; + } + + @Override + public byte byteAt(int index) { + return byteArray[index]; + } + + @Override + public byte[] copyArrayOfRange(int from, int to) { + return Arrays.copyOfRange(byteArray, from, to); + } + + @Override + public String toHexString() { + return ByteUtil.toHexString(byteArray); + } + + @Override + public String toHexString(int off, int length) { + return ByteUtil.toHexString(byteArray, off, length); + } + + @Nonnull + @Override + public byte[] asUnsafeByteArray() { + return byteArray; + } + + @Override + public String toString() { + return toPrintableString(); + } +} diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java new file mode 100644 index 00000000000..a91fde0b7f4 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java @@ -0,0 +1,123 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.core.types.bytes; + +/** + * A {@link BytesSlice} is a subsequence of bytes backed by another broader byte sequence. + */ +public interface BytesSlice extends HexPrintableBytes { + + /** + * Copies the specified range of the specified array into a new array. + * The initial index of the range (from) must lie between zero + * and original.length, inclusive. The value at + * original[from] is placed into the initial element of the copy + * (unless from == original.length or from == to). + * Values from subsequent elements in the original array are placed into + * subsequent elements in the copy. The final index of the range + * (to), which must be greater than or equal to from, + * may be greater than original.length, in which case + * (byte)0 is placed in all elements of the copy whose index is + * greater than or equal to original.length - from. The length + * of the returned array will be to - from. + * + * @param from the initial index of the range to be copied, inclusive + * @param to the final index of the range to be copied, exclusive. + * (This index may lie outside the array.) + * @return a new array containing the specified range from the original array, + * truncated or padded with zeros to obtain the required length + * @throws ArrayIndexOutOfBoundsException if {@code from < 0} + * or {@code from > original.length} + * @throws IllegalArgumentException if from > to + * @throws NullPointerException if original is null + */ + byte[] copyArrayOfRange(int from, int to); + + default Bytes copyBytesOfRange(int from, int to) { + return Bytes.of(copyArrayOfRange(from, to)); + } + + default BytesSlice slice(int from, int to) { + return new BytesSliceImpl(this, from, to); + } +} + +class BytesSliceImpl implements BytesSlice { + + private final BytesSlice originBytes; + + private final int from; + private final int to; + + BytesSliceImpl(BytesSlice originBytes, int from, int to) { + this.originBytes = originBytes; + + if (from < 0) { + throw new IndexOutOfBoundsException(from + " < " + 0); + } + if (from >= to) { + throw new IndexOutOfBoundsException(from + " > " + to); + } + if (to > originBytes.length()) { + throw new IndexOutOfBoundsException(to + " > " + "length"); + } + + this.from = from; + this.to = to; + } + + @Override + public int length() { + return to - from; + } + + @Override + public byte byteAt(int index) { + if (index < 0 || index >= length()) { + throw new IndexOutOfBoundsException("invalid index: " + index); + } + return originBytes.byteAt(from + index); + } + + @Override + public byte[] copyArrayOfRange(int from, int to) { + if (from < 0 || from >= to || to > length()) { + throw new IndexOutOfBoundsException("invalid 'from' and/or 'to': [" + from + ";" + to + ")"); + } + return originBytes.copyArrayOfRange(this.from + from, this.from + to); + } + + @Override + public String toHexString(int off, int length) { + if (off < 0 || length < 0 || off + length > length()) { + throw new IndexOutOfBoundsException("invalid 'off' and/or 'length': " + off + "; " + length); + } + return originBytes.toHexString(from + off, length); + } + + @Override + public String toHexString() { + return toHexString(0, length()); + } + + @Override + public String toString() { + return toPrintableString(); + } +} diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java new file mode 100644 index 00000000000..0eeeebd329c --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java @@ -0,0 +1,92 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.core.types.bytes; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Objects; + +/** + * A {@link HexPrintableBytes} is an extension of the {@link PrintableBytes} class with capabilities to + * represent it in hexadecimal format. + */ +public interface HexPrintableBytes extends PrintableBytes { + + Formatter SIMPLE_HEX_FORMATTER = new PrintableBytesHexFormatter(); + Formatter SIMPLE_JSON_HEX_FORMATTER = new PrintableBytesJsonHexFormatter(); + + + @Nullable + static String toHexString(@Nullable HexPrintableBytes bytes, @Nullable String defaultValue) { + if (bytes == null) { + return defaultValue; + } + return bytes.toHexString(); + } + + @Nullable + static String toHexString(@Nullable HexPrintableBytes bytes) { + return toHexString(bytes, null); + } + + default String toPrintableString(@Nonnull Formatter formatter, int off, int length) { + return formatter.toFormattedString(this, off, length); + } + + default String toPrintableString(@Nonnull Formatter formatter) { + return formatter.toFormattedString(this, 0, length()); + } + + @Override + default String toPrintableString() { + return toPrintableString(SIMPLE_HEX_FORMATTER); + } + + default String toJsonHexFormattedString() { + return toPrintableString(SIMPLE_JSON_HEX_FORMATTER); + } + + String toHexString(int off, int length); + + String toHexString(); +} + +class PrintableBytesHexFormatter implements PrintableBytes.Formatter { + + @Override + public String toFormattedString(@Nonnull HexPrintableBytes printableBytes, int off, int length) { + int bytesLen = Objects.requireNonNull(printableBytes).length(); + if (off + length > bytesLen) { + throw new IndexOutOfBoundsException("invalid 'off' and/or 'length': " + off + "; " + length); + } + + if (length > 32) { + return printableBytes.toHexString(off, 15) + ".." + printableBytes.toHexString(off + length - 15, 15); + } + return printableBytes.toHexString(off, length); + } +} + +class PrintableBytesJsonHexFormatter extends PrintableBytesHexFormatter { + + @Override + public String toFormattedString(@Nonnull HexPrintableBytes printableBytes, int off, int length) { + return "0x" + super.toFormattedString(printableBytes, off, length); + } +} diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/PrintableBytes.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/PrintableBytes.java new file mode 100644 index 00000000000..10b21f00c92 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/PrintableBytes.java @@ -0,0 +1,35 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.core.types.bytes; + +import javax.annotation.Nonnull; + +/** + * A {@link PrintableBytes} is a sequence of byte values that + * can be represented as a {@link String} value. + */ +public interface PrintableBytes extends ByteSequence { + + interface Formatter { + String toFormattedString(@Nonnull T printableBytes, int off, int length); + } + + String toPrintableString(); + +} diff --git a/rskj-core/src/main/java/co/rsk/net/discovery/PacketDecoder.java b/rskj-core/src/main/java/co/rsk/net/discovery/PacketDecoder.java index 96e2d3a2adc..743a1e5a903 100644 --- a/rskj-core/src/main/java/co/rsk/net/discovery/PacketDecoder.java +++ b/rskj-core/src/main/java/co/rsk/net/discovery/PacketDecoder.java @@ -19,13 +19,13 @@ package co.rsk.net.discovery; +import co.rsk.core.types.bytes.Bytes; import co.rsk.net.discovery.message.MessageDecoder; import co.rsk.net.discovery.message.PeerDiscoveryMessage; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.socket.DatagramPacket; import io.netty.handler.codec.MessageToMessageDecoder; -import org.ethereum.util.ByteUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,7 +48,7 @@ public DiscoveryEvent decodeMessage(ChannelHandlerContext ctx, byte[] encoded, I PeerDiscoveryMessage msg = MessageDecoder.decode(encoded); return new DiscoveryEvent(msg, sender); } catch (Exception e) { - logger.error("Exception processing inbound message from {} : {}", ctx.channel().remoteAddress(), ByteUtil.toHexString(encoded), e); + logger.error("Exception processing inbound message from {} : {}", ctx.channel().remoteAddress(), Bytes.of(encoded), e); throw e; } } diff --git a/rskj-core/src/main/java/co/rsk/net/discovery/message/PeerDiscoveryMessage.java b/rskj-core/src/main/java/co/rsk/net/discovery/message/PeerDiscoveryMessage.java index ab98a03f4db..5aef6eac662 100644 --- a/rskj-core/src/main/java/co/rsk/net/discovery/message/PeerDiscoveryMessage.java +++ b/rskj-core/src/main/java/co/rsk/net/discovery/message/PeerDiscoveryMessage.java @@ -18,6 +18,7 @@ package co.rsk.net.discovery.message; +import co.rsk.core.types.bytes.Bytes; import co.rsk.net.NodeID; import co.rsk.net.discovery.PeerDiscoveryException; import org.apache.commons.lang3.builder.ToStringBuilder; @@ -179,10 +180,10 @@ public DiscoveryMessageType getMessageType() { @Override public String toString() { return new ToStringBuilder(this) - .append("mdc", ByteUtil.toHexString(mdc)) - .append("signature", ByteUtil.toHexString(signature)) - .append("type", ByteUtil.toHexString(type)) - .append("data", ByteUtil.toHexString(data)).toString(); + .append("mdc", Bytes.of(mdc)) + .append("signature", Bytes.of(signature)) + .append("type", Bytes.of(type)) + .append("data", Bytes.of(data)).toString(); } protected String extractMessageId(RLPItem chk) { diff --git a/rskj-core/src/main/java/co/rsk/net/handler/quota/TxQuota.java b/rskj-core/src/main/java/co/rsk/net/handler/quota/TxQuota.java index 5d333737d5f..ac1d0a11a10 100644 --- a/rskj-core/src/main/java/co/rsk/net/handler/quota/TxQuota.java +++ b/rskj-core/src/main/java/co/rsk/net/handler/quota/TxQuota.java @@ -81,11 +81,15 @@ private synchronized boolean acceptVirtualGasConsumption(double virtualGasToCons if (this.availableVirtualGas < virtualGasToConsume) { String acceptanceNote = forcingAcceptance ? "Forcing tx acceptance" : "NOT enough virtualGas"; - logger.warn("{} for blockNumber [{}], sender [{}] and tx [{}]: availableVirtualGas=[{}], virtualGasToConsume=[{}]", acceptanceNote, blockNumber, sender, tx, this.availableVirtualGas, virtualGasToConsume); + if (logger.isWarnEnabled()) { + logger.warn("{} for blockNumber [{}], sender [{}] and tx [{}]: availableVirtualGas=[{}], virtualGasToConsume=[{}]", acceptanceNote, blockNumber, sender, tx.getHash(), this.availableVirtualGas, virtualGasToConsume); + } return false; } - logger.trace("Enough virtualGas for blockNumber [{}], sender [{}] and tx [{}]: availableVirtualGas=[{}], virtualGasToConsume=[{}]", blockNumber, sender, tx, this.availableVirtualGas, virtualGasToConsume); + if (logger.isTraceEnabled()) { + logger.trace("Enough virtualGas for blockNumber [{}], sender [{}] and tx [{}]: availableVirtualGas=[{}], virtualGasToConsume=[{}]", blockNumber, sender, tx.getHash(), this.availableVirtualGas, virtualGasToConsume); + } this.availableVirtualGas -= virtualGasToConsume; return true; } diff --git a/rskj-core/src/main/java/co/rsk/pcc/NativeContract.java b/rskj-core/src/main/java/co/rsk/pcc/NativeContract.java index 45d34ea7526..281d498d66c 100644 --- a/rskj-core/src/main/java/co/rsk/pcc/NativeContract.java +++ b/rskj-core/src/main/java/co/rsk/pcc/NativeContract.java @@ -19,10 +19,10 @@ package co.rsk.pcc; import co.rsk.core.RskAddress; +import co.rsk.core.types.bytes.Bytes; import co.rsk.panic.PanicProcessor; import co.rsk.pcc.exception.NativeContractIllegalArgumentException; import org.ethereum.config.blockchain.upgrades.ActivationConfig; -import org.ethereum.util.ByteUtil; import org.ethereum.vm.PrecompiledContractArgs; import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.exception.VMException; @@ -119,7 +119,7 @@ public byte[] execute(byte[] data) throws VMException { // No function found with the given data? => halt! if (!methodWithArguments.isPresent()) { - String errorMessage = String.format("Invalid data given: %s.", ByteUtil.toHexString(data)); + String errorMessage = String.format("Invalid data given: %s.", Bytes.of(data)); logger.info(errorMessage); throw new NativeContractIllegalArgumentException(errorMessage); } @@ -174,7 +174,7 @@ public byte[] execute(byte[] data) throws VMException { private Optional parseData(byte[] data) { if (data != null && (data.length >= 1 && data.length <= 3)) { - logger.warn("Invalid function signature {}.", ByteUtil.toHexString(data)); + logger.warn("Invalid function signature {}.", Bytes.of(data)); return Optional.empty(); } @@ -194,7 +194,7 @@ private Optional parseData(byte[] data) { ).findFirst(); if (!maybeMethod.isPresent()) { - logger.warn("Invalid function signature {}.", ByteUtil.toHexString(encodedSignature)); + logger.warn("Invalid function signature {}.", Bytes.of(encodedSignature)); return Optional.empty(); } @@ -209,7 +209,7 @@ private Optional parseData(byte[] data) { Object[] arguments = method.getFunction().decode(data); return Optional.of(method.new WithArguments(arguments, data)); } catch (Exception e) { - logger.warn(String.format("Invalid arguments %s for function %s.", ByteUtil.toHexString(data), ByteUtil.toHexString(encodedSignature)), e); + logger.warn(String.format("Invalid arguments %s for function %s.", Bytes.of(data), Bytes.of(encodedSignature)), e); return Optional.empty(); } } diff --git a/rskj-core/src/main/java/co/rsk/pcc/bto/DeriveExtendedPublicKey.java b/rskj-core/src/main/java/co/rsk/pcc/bto/DeriveExtendedPublicKey.java index 9592e402c44..989dad2004e 100644 --- a/rskj-core/src/main/java/co/rsk/pcc/bto/DeriveExtendedPublicKey.java +++ b/rskj-core/src/main/java/co/rsk/pcc/bto/DeriveExtendedPublicKey.java @@ -24,8 +24,9 @@ import co.rsk.bitcoinj.crypto.HDKeyDerivation; import co.rsk.bitcoinj.crypto.HDUtils; import co.rsk.pcc.ExecutionEnvironment; -import co.rsk.pcc.exception.NativeContractIllegalArgumentException; import co.rsk.pcc.NativeMethod; +import co.rsk.pcc.exception.NativeContractIllegalArgumentException; +import co.rsk.util.StringUtils; import org.ethereum.core.CallTransaction; import java.util.Arrays; @@ -126,7 +127,7 @@ private void throwInvalidPath(String path) throws NativeContractIllegalArgumentE } private String getInvalidPathErrorMessage(String path) { - return String.format("Invalid path '%s'", path); + return String.format("Invalid path '%s'", StringUtils.trim(path)); } private boolean isDecimal(String s) { diff --git a/rskj-core/src/main/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKey.java b/rskj-core/src/main/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKey.java index 16e2f3f975d..924af82a306 100644 --- a/rskj-core/src/main/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKey.java +++ b/rskj-core/src/main/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKey.java @@ -21,8 +21,9 @@ import co.rsk.bitcoinj.core.NetworkParameters; import co.rsk.bitcoinj.crypto.DeterministicKey; import co.rsk.pcc.ExecutionEnvironment; -import co.rsk.pcc.exception.NativeContractIllegalArgumentException; import co.rsk.pcc.NativeMethod; +import co.rsk.pcc.exception.NativeContractIllegalArgumentException; +import co.rsk.util.StringUtils; import org.ethereum.core.CallTransaction; /** @@ -40,7 +41,7 @@ public class ExtractPublicKeyFromExtendedPublicKey extends NativeMethod { private final HDWalletUtilsHelper helper; - private final static String INVALID_EXTENDED_PUBLIC_KEY = "Invalid extended public key '%s"; + private final static String INVALID_EXTENDED_PUBLIC_KEY = "Invalid extended public key '%s'"; public ExtractPublicKeyFromExtendedPublicKey(ExecutionEnvironment executionEnvironment, HDWalletUtilsHelper helper) { super(executionEnvironment); @@ -64,7 +65,7 @@ public Object execute(Object[] arguments) throws NativeContractIllegalArgumentEx try { key = DeterministicKey.deserializeB58(xpub, params); } catch (IllegalArgumentException e) { - throw new NativeContractIllegalArgumentException(String.format(INVALID_EXTENDED_PUBLIC_KEY, xpub), e); + throw new NativeContractIllegalArgumentException(String.format(INVALID_EXTENDED_PUBLIC_KEY, StringUtils.trim(xpub)), e); } return key.getPubKeyPoint().getEncoded(true); diff --git a/rskj-core/src/main/java/co/rsk/pcc/bto/GetMultisigScriptHash.java b/rskj-core/src/main/java/co/rsk/pcc/bto/GetMultisigScriptHash.java index c4524d3fcb0..a0b91cb143f 100644 --- a/rskj-core/src/main/java/co/rsk/pcc/bto/GetMultisigScriptHash.java +++ b/rskj-core/src/main/java/co/rsk/pcc/bto/GetMultisigScriptHash.java @@ -21,11 +21,11 @@ import co.rsk.bitcoinj.core.BtcECKey; import co.rsk.bitcoinj.script.Script; import co.rsk.bitcoinj.script.ScriptBuilder; +import co.rsk.core.types.bytes.Bytes; import co.rsk.pcc.ExecutionEnvironment; import co.rsk.pcc.NativeMethod; import co.rsk.pcc.exception.NativeContractIllegalArgumentException; import org.ethereum.core.CallTransaction; -import org.ethereum.util.ByteUtil; import java.math.BigInteger; import java.util.ArrayList; @@ -118,7 +118,7 @@ public Object execute(Object[] arguments) throws NativeContractIllegalArgumentEx btcPublicKeys.add(btcPublicKey); } catch (IllegalArgumentException e) { throw new NativeContractIllegalArgumentException(String.format( - "Invalid public key format: %s", ByteUtil.toHexString(publicKey) + "Invalid public key format: %s", Bytes.of(publicKey) ), e); } } diff --git a/rskj-core/src/main/java/co/rsk/pcc/bto/HDWalletUtilsHelper.java b/rskj-core/src/main/java/co/rsk/pcc/bto/HDWalletUtilsHelper.java index 9b7ce14c813..08073811b8d 100644 --- a/rskj-core/src/main/java/co/rsk/pcc/bto/HDWalletUtilsHelper.java +++ b/rskj-core/src/main/java/co/rsk/pcc/bto/HDWalletUtilsHelper.java @@ -2,6 +2,7 @@ import co.rsk.bitcoinj.core.NetworkParameters; import co.rsk.pcc.exception.NativeContractIllegalArgumentException; +import co.rsk.util.StringUtils; public class HDWalletUtilsHelper { public NetworkParameters validateAndExtractNetworkFromExtendedPublicKey(String xpub) throws NativeContractIllegalArgumentException { @@ -15,7 +16,7 @@ public NetworkParameters validateAndExtractNetworkFromExtendedPublicKey(String x } else if (xpub.startsWith("tpub")) { return NetworkParameters.fromID(NetworkParameters.ID_TESTNET); } else { - throw new NativeContractIllegalArgumentException(String.format("Invalid extended public key '%s'", xpub)); + throw new NativeContractIllegalArgumentException(String.format("Invalid extended public key '%s'", StringUtils.trim(xpub))); } } } diff --git a/rskj-core/src/main/java/co/rsk/pcc/bto/ToBase58Check.java b/rskj-core/src/main/java/co/rsk/pcc/bto/ToBase58Check.java index 9e413842a79..7b69a0b0cbb 100644 --- a/rskj-core/src/main/java/co/rsk/pcc/bto/ToBase58Check.java +++ b/rskj-core/src/main/java/co/rsk/pcc/bto/ToBase58Check.java @@ -18,11 +18,11 @@ package co.rsk.pcc.bto; +import co.rsk.core.types.bytes.Bytes; import co.rsk.pcc.ExecutionEnvironment; -import co.rsk.pcc.exception.NativeContractIllegalArgumentException; import co.rsk.pcc.NativeMethod; +import co.rsk.pcc.exception.NativeContractIllegalArgumentException; import org.ethereum.core.CallTransaction; -import org.ethereum.util.ByteUtil; import java.math.BigInteger; @@ -77,7 +77,7 @@ public Object execute(Object[] arguments) throws NativeContractIllegalArgumentEx if (hash.length != 20) { throw new NativeContractIllegalArgumentException(String.format( HASH_INVALID, - ByteUtil.toHexString(hash), hash.length + Bytes.of(hash), hash.length )); } diff --git a/rskj-core/src/main/java/co/rsk/peg/Bridge.java b/rskj-core/src/main/java/co/rsk/peg/Bridge.java index 1c5cfb82024..6af54db63e1 100644 --- a/rskj-core/src/main/java/co/rsk/peg/Bridge.java +++ b/rskj-core/src/main/java/co/rsk/peg/Bridge.java @@ -22,6 +22,7 @@ import co.rsk.bitcoinj.core.*; import co.rsk.bitcoinj.script.Script; import co.rsk.bitcoinj.store.BlockStoreException; +import co.rsk.core.types.bytes.Bytes; import co.rsk.peg.constants.BridgeConstants; import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; @@ -301,7 +302,7 @@ BridgeParsedData parseData(byte[] data) { BridgeParsedData bridgeParsedData = new BridgeParsedData(); if (data != null && (data.length >= 1 && data.length <= 3)) { - logger.warn("Invalid function signature {}.", ByteUtil.toHexString(data)); + logger.warn("Invalid function signature {}.", Bytes.of(data)); return null; } @@ -312,14 +313,14 @@ BridgeParsedData parseData(byte[] data) { byte[] functionSignature = Arrays.copyOfRange(data, 0, 4); Optional invokedMethod = BridgeMethods.findBySignature(functionSignature); if (!invokedMethod.isPresent()) { - logger.warn("Invalid function signature {}.", ByteUtil.toHexString(functionSignature)); + logger.warn("Invalid function signature {}.", Bytes.of(functionSignature)); return null; } bridgeParsedData.bridgeMethod = invokedMethod.get(); try { bridgeParsedData.args = bridgeParsedData.bridgeMethod.getFunction().decode(data); } catch (Exception e) { - logger.warn("Invalid function arguments {} for function {}.", ByteUtil.toHexString(data), ByteUtil.toHexString(functionSignature)); + logger.warn("Invalid function arguments {} for function {}.", Bytes.of(data), Bytes.of(functionSignature)); return null; } } @@ -370,7 +371,7 @@ public byte[] execute(byte[] data) throws VMException { // Function parsing from data returned null => invalid function selected, halt! if (bridgeParsedData == null) { - String errorMessage = String.format("Invalid data given: %s.", ByteUtil.toHexString(data)); + String errorMessage = String.format("Invalid data given: %s.", Bytes.of(data)); logger.info("[execute] {}", errorMessage); if (!activations.isActive(ConsensusRule.RSKIP88)) { return null; @@ -527,7 +528,7 @@ public void receiveHeaders(Object[] args) throws VMException { BtcBlock header = bridgeConstants.getBtcParams().getDefaultSerializer().makeBlock(btcBlockSerialized); btcBlockArray[i] = header; } catch (ProtocolException e) { - throw new BridgeIllegalArgumentException("Block " + i + " could not be parsed " + ByteUtil.toHexString(btcBlockSerialized), e); + throw new BridgeIllegalArgumentException("Block " + i + " could not be parsed " + Bytes.of(btcBlockSerialized), e); } } try { @@ -599,7 +600,7 @@ public void addSignature(Object[] args) throws VMException { try { federatorPublicKey = BtcECKey.fromPublicOnly(federatorPublicKeySerialized); } catch (Exception e) { - throw new BridgeIllegalArgumentException("Public key could not be parsed " + ByteUtil.toHexString(federatorPublicKeySerialized), e); + throw new BridgeIllegalArgumentException("Public key could not be parsed " + Bytes.of(federatorPublicKeySerialized), e); } Object[] signaturesObjectArray = (Object[]) args[1]; if (signaturesObjectArray.length == 0) { @@ -611,13 +612,13 @@ public void addSignature(Object[] args) throws VMException { try { BtcECKey.ECDSASignature.decodeFromDER((byte[])signatureObject); } catch (Exception e) { - throw new BridgeIllegalArgumentException("Signature could not be parsed " + ByteUtil.toHexString(signatureByteArray), e); + throw new BridgeIllegalArgumentException("Signature could not be parsed " + Bytes.of(signatureByteArray), e); } signatures.add(signatureByteArray); } byte[] rskTxHash = (byte[]) args[2]; if (rskTxHash.length!=32) { - throw new BridgeIllegalArgumentException("Invalid rsk tx hash " + ByteUtil.toHexString(rskTxHash)); + throw new BridgeIllegalArgumentException("Invalid rsk tx hash " + Bytes.of(rskTxHash)); } try { bridgeSupport.addSignature(federatorPublicKey, signatures, rskTxHash); diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java index b97ecfde42e..a027e0fdd17 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -29,6 +29,7 @@ import co.rsk.bitcoinj.store.BlockStoreException; import co.rsk.bitcoinj.wallet.SendRequest; import co.rsk.bitcoinj.wallet.Wallet; +import co.rsk.core.types.bytes.Bytes; import co.rsk.peg.constants.BridgeConstants; import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; @@ -1517,7 +1518,7 @@ private void processSigning( "Malformed signature for input {} of tx {}: {}", i, new Keccak256(rskTxHash), - ByteUtil.toHexString(signatures.get(i)) + Bytes.of(signatures.get(i)) ); return; } @@ -1528,7 +1529,7 @@ private void processSigning( logger.warn( "Signature {} {} is not valid for hash {} and public key {}", i, - ByteUtil.toHexString(sig.encodeToDER()), + Bytes.of(sig.encodeToDER()), sighash, federatorBtcPublicKey ); @@ -1538,7 +1539,7 @@ private void processSigning( TransactionSignature txSig = new TransactionSignature(sig, BtcTransaction.SigHash.ALL, false); txSigs.add(txSig); if (!txSig.isCanonical()) { - logger.warn("Signature {} {} is not canonical.", i, ByteUtil.toHexString(signatures.get(i))); + logger.warn("Signature {} {} is not canonical.", i, Bytes.of(signatures.get(i))); return; } } @@ -1586,7 +1587,7 @@ private void processSigning( } if (BridgeUtils.hasEnoughSignatures(btcContext, btcTx)) { - logger.info("Tx fully signed {}. Hex: {}", btcTx, Hex.toHexString(btcTx.bitcoinSerialize())); + logger.info("Tx fully signed {}. Hex: {}", btcTx, Bytes.of(btcTx.bitcoinSerialize())); provider.getPegoutsWaitingForSignatures().remove(new Keccak256(rskTxHash)); eventLogger.logReleaseBtc(btcTx, rskTxHash); @@ -2317,7 +2318,7 @@ private ABICallVoteResult executeVoteFederationChangeFunction(boolean dryRun, AB publicKey = BtcECKey.fromPublicOnly(publicKeyBytes); publicKeyEc = ECKey.fromPublicOnly(publicKeyBytes); } catch (Exception e) { - throw new BridgeIllegalArgumentException("Public key could not be parsed " + ByteUtil.toHexString(publicKeyBytes), e); + throw new BridgeIllegalArgumentException("Public key could not be parsed " + Bytes.of(publicKeyBytes), e); } executionResult = addFederatorPublicKeyMultikey(dryRun, publicKey, publicKeyEc, publicKeyEc); result = new ABICallVoteResult(executionResult == 1, executionResult); @@ -2329,19 +2330,19 @@ private ABICallVoteResult executeVoteFederationChangeFunction(boolean dryRun, AB try { btcPublicKey = BtcECKey.fromPublicOnly(callSpec.getArguments()[0]); } catch (Exception e) { - throw new BridgeIllegalArgumentException("BTC public key could not be parsed " + ByteUtil.toHexString(callSpec.getArguments()[0]), e); + throw new BridgeIllegalArgumentException("BTC public key could not be parsed " + Bytes.of(callSpec.getArguments()[0]), e); } try { rskPublicKey = ECKey.fromPublicOnly(callSpec.getArguments()[1]); } catch (Exception e) { - throw new BridgeIllegalArgumentException("RSK public key could not be parsed " + ByteUtil.toHexString(callSpec.getArguments()[1]), e); + throw new BridgeIllegalArgumentException("RSK public key could not be parsed " + Bytes.of(callSpec.getArguments()[1]), e); } try { mstPublicKey = ECKey.fromPublicOnly(callSpec.getArguments()[2]); } catch (Exception e) { - throw new BridgeIllegalArgumentException("MST public key could not be parsed " + ByteUtil.toHexString(callSpec.getArguments()[2]), e); + throw new BridgeIllegalArgumentException("MST public key could not be parsed " + Bytes.of(callSpec.getArguments()[2]), e); } executionResult = addFederatorPublicKeyMultikey(dryRun, btcPublicKey, rskPublicKey, mstPublicKey); result = new ABICallVoteResult(executionResult == 1, executionResult); @@ -2670,7 +2671,7 @@ public void registerBtcCoinbaseTransaction(byte[] btcTxSerialized, Sha256Hash bl } } catch (VerificationException e) { logger.warn("[btcTx:{}] PartialMerkleTree could not be parsed", btcTxHash); - throw new BridgeIllegalArgumentException(String.format("PartialMerkleTree could not be parsed %s", ByteUtil.toHexString(pmtSerialized)), e); + throw new BridgeIllegalArgumentException(String.format("PartialMerkleTree could not be parsed %s", Bytes.of(pmtSerialized)), e); } // Check merkle root equals btc block merkle root at the specified height in the btc best chain diff --git a/rskj-core/src/main/java/co/rsk/peg/bitcoin/UtxoUtils.java b/rskj-core/src/main/java/co/rsk/peg/bitcoin/UtxoUtils.java index 0704bd24f0c..6177264287d 100644 --- a/rskj-core/src/main/java/co/rsk/peg/bitcoin/UtxoUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/bitcoin/UtxoUtils.java @@ -4,6 +4,7 @@ import co.rsk.bitcoinj.core.Coin; import co.rsk.bitcoinj.core.TransactionInput; import co.rsk.bitcoinj.core.VarInt; +import co.rsk.core.types.bytes.Bytes; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -11,7 +12,6 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; -import org.spongycastle.util.encoders.Hex; public final class UtxoUtils { @@ -40,7 +40,7 @@ public static List decodeOutpointValues(byte[] encodedOutpointValues) { } catch (Exception ex) { throw new InvalidOutpointValueException( String.format("Invalid value with invalid VarInt format: %s", - Hex.toHexString(encodedOutpointValues).toUpperCase() + Bytes.of(encodedOutpointValues).toPrintableString().toUpperCase() ), ex ); diff --git a/rskj-core/src/main/java/co/rsk/peg/federation/FederationMember.java b/rskj-core/src/main/java/co/rsk/peg/federation/FederationMember.java index bc42ea29c0f..16d68d6f954 100644 --- a/rskj-core/src/main/java/co/rsk/peg/federation/FederationMember.java +++ b/rskj-core/src/main/java/co/rsk/peg/federation/FederationMember.java @@ -19,6 +19,7 @@ package co.rsk.peg.federation; import co.rsk.bitcoinj.core.BtcECKey; +import co.rsk.util.StringUtils; import org.ethereum.crypto.ECKey; import org.ethereum.util.ByteUtil; import org.ethereum.util.RLP; @@ -79,7 +80,7 @@ public static KeyType byValue(String value) { case "btc": return KeyType.BTC; default: - throw new IllegalArgumentException(String.format("Invalid value for FederationMember.KeyType: %s", value)); + throw new IllegalArgumentException(String.format("Invalid value for FederationMember.KeyType: %s", StringUtils.trim(value))); } } } diff --git a/rskj-core/src/main/java/co/rsk/peg/pegininstructions/PeginInstructionsProvider.java b/rskj-core/src/main/java/co/rsk/peg/pegininstructions/PeginInstructionsProvider.java index ea249c5f8fb..53b2b874c48 100644 --- a/rskj-core/src/main/java/co/rsk/peg/pegininstructions/PeginInstructionsProvider.java +++ b/rskj-core/src/main/java/co/rsk/peg/pegininstructions/PeginInstructionsProvider.java @@ -6,6 +6,8 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; + +import co.rsk.core.types.bytes.Bytes; import org.bouncycastle.util.encoders.Hex; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,7 +36,7 @@ public Optional buildPeginInstructions(BtcTransaction btcTx) throw new PeginInstructionsException(message, e); } - logger.trace("[buildPeginInstructions] OP_RETURN data: {}", Hex.toHexString(opReturnOutputData)); + logger.trace("[buildPeginInstructions] OP_RETURN data: {}", Bytes.of(opReturnOutputData)); int protocolVersion = PeginInstructionsBase.extractProtocolVersion(opReturnOutputData); diff --git a/rskj-core/src/main/java/co/rsk/remasc/RemascContract.java b/rskj-core/src/main/java/co/rsk/remasc/RemascContract.java index a938f4c7d59..23c569d37e9 100644 --- a/rskj-core/src/main/java/co/rsk/remasc/RemascContract.java +++ b/rskj-core/src/main/java/co/rsk/remasc/RemascContract.java @@ -20,13 +20,13 @@ import co.rsk.config.RemascConfig; import co.rsk.core.RskAddress; +import co.rsk.core.types.bytes.Bytes; import co.rsk.panic.PanicProcessor; import co.rsk.rpc.modules.trace.ProgramSubtrace; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.core.CallTransaction; import org.ethereum.db.ByteArrayWrapper; -import org.ethereum.util.ByteUtil; import org.ethereum.vm.DataWord; import org.ethereum.vm.PrecompiledContractArgs; import org.ethereum.vm.PrecompiledContracts; @@ -130,7 +130,7 @@ private CallTransaction.Function getFunction(byte[] data) { function = PROCESS_MINERS_FEES; } else { if (data.length != 4) { - logger.warn("Invalid function: signature longer than expected {}.", ByteUtil.toHexString(data)); + logger.warn("Invalid function: signature longer than expected {}.", Bytes.of(data)); throw new RemascInvalidInvocationException("Invalid function signature"); } @@ -138,7 +138,7 @@ private CallTransaction.Function getFunction(byte[] data) { function = functions.get(new ByteArrayWrapper(functionSignature)); if (function == null) { - logger.warn("Invalid function: signature does not match an existing function {}.", ByteUtil.toHexString(functionSignature)); + logger.warn("Invalid function: signature does not match an existing function {}.", Bytes.of(functionSignature)); throw new RemascInvalidInvocationException("Invalid function signature"); } } diff --git a/rskj-core/src/main/java/co/rsk/util/StringUtils.java b/rskj-core/src/main/java/co/rsk/util/StringUtils.java new file mode 100644 index 00000000000..7f6019d082e --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/util/StringUtils.java @@ -0,0 +1,40 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.util; + +import javax.annotation.Nullable; + +public class StringUtils { + + private static final int DEFAULT_MAX_LEN = 32; + + public static String trim(@Nullable String src) { + return trim(src, DEFAULT_MAX_LEN); + } + + public static String trim(@Nullable String src, int maxLength) { + if (maxLength < 0) { + throw new IllegalArgumentException("maxLength: " + maxLength); + } + if (src == null || src.length() <= maxLength) { + return src; + } + return src.substring(0, maxLength) + "..."; + } +} diff --git a/rskj-core/src/main/java/co/rsk/validators/BlockRootValidationRule.java b/rskj-core/src/main/java/co/rsk/validators/BlockRootValidationRule.java index 034e9d808c9..cad08aff0d4 100644 --- a/rskj-core/src/main/java/co/rsk/validators/BlockRootValidationRule.java +++ b/rskj-core/src/main/java/co/rsk/validators/BlockRootValidationRule.java @@ -19,11 +19,11 @@ package co.rsk.validators; import co.rsk.core.bc.BlockHashesHelper; +import co.rsk.core.types.bytes.Bytes; import co.rsk.panic.PanicProcessor; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.Block; -import org.ethereum.util.ByteUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,7 +55,7 @@ public boolean isValid(Block block) { if (!Arrays.equals(blockTxRootHash, txListRootHash)) { String message = String.format("Block's given Trie Hash doesn't match: %s != %s", - ByteUtil.toHexString(blockTxRootHash), ByteUtil.toHexString(txListRootHash)); + Bytes.of(blockTxRootHash), Bytes.of(txListRootHash)); logger.warn(message); panicProcessor.panic("invalidtrie", message); diff --git a/rskj-core/src/main/java/co/rsk/validators/BlockUnclesHashValidationRule.java b/rskj-core/src/main/java/co/rsk/validators/BlockUnclesHashValidationRule.java index 3d25bc706c1..037aab5b5c7 100644 --- a/rskj-core/src/main/java/co/rsk/validators/BlockUnclesHashValidationRule.java +++ b/rskj-core/src/main/java/co/rsk/validators/BlockUnclesHashValidationRule.java @@ -1,5 +1,6 @@ package co.rsk.validators; +import co.rsk.core.types.bytes.Bytes; import co.rsk.panic.PanicProcessor; import org.ethereum.core.Block; import org.ethereum.core.BlockHeader; @@ -20,7 +21,7 @@ public boolean isValid(Block block) { if (!ByteUtil.fastEquals(unclesHeader, unclesBlock)) { String message = String.format("Block's given Uncle Hash doesn't match: %s != %s", - ByteUtil.toHexString(unclesHeader), ByteUtil.toHexString(unclesBlock)); + Bytes.of(unclesHeader), Bytes.of(unclesBlock)); logger.warn(message); panicProcessor.panic("invaliduncle", message); return false; diff --git a/rskj-core/src/main/java/org/ethereum/core/Block.java b/rskj-core/src/main/java/org/ethereum/core/Block.java index 178782b70cb..627662d0519 100644 --- a/rskj-core/src/main/java/org/ethereum/core/Block.java +++ b/rskj-core/src/main/java/org/ethereum/core/Block.java @@ -23,12 +23,12 @@ import co.rsk.core.Coin; import co.rsk.core.RskAddress; import co.rsk.core.bc.BlockHashesHelper; +import co.rsk.core.types.bytes.Bytes; import co.rsk.crypto.Keccak256; import co.rsk.panic.PanicProcessor; import com.google.common.collect.ImmutableList; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.BigIntegers; -import org.ethereum.util.ByteUtil; import org.ethereum.util.RLP; import javax.annotation.Nonnull; @@ -208,7 +208,7 @@ public Coin getMinimumGasPrice() { @Override public String toString() { StringBuilder toStringBuff = new StringBuilder(); - toStringBuff.append(ByteUtil.toHexString(this.getEncoded())).append("\n"); + toStringBuff.append(Bytes.of(this.getEncoded())).append("\n"); toStringBuff.append("BlockData [ "); toStringBuff.append("hash=").append(this.getHash()).append("\n"); toStringBuff.append(header.toString()); diff --git a/rskj-core/src/main/java/org/ethereum/core/BlockIdentifier.java b/rskj-core/src/main/java/org/ethereum/core/BlockIdentifier.java index 4a3729e18c8..2d7862d1016 100644 --- a/rskj-core/src/main/java/org/ethereum/core/BlockIdentifier.java +++ b/rskj-core/src/main/java/org/ethereum/core/BlockIdentifier.java @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -import org.ethereum.util.ByteUtil; +import co.rsk.core.types.bytes.Bytes; import org.ethereum.util.RLP; import org.ethereum.util.RLPList; @@ -74,7 +74,7 @@ public byte[] getEncoded() { @Override public String toString() { return "BlockIdentifier {" + - "hash=" + ByteUtil.toHexString(hash) + + "hash=" + Bytes.of(hash) + ", number=" + number + '}'; } diff --git a/rskj-core/src/main/java/org/ethereum/core/Bloom.java b/rskj-core/src/main/java/org/ethereum/core/Bloom.java index b5061c63bec..ff3690d9208 100644 --- a/rskj-core/src/main/java/org/ethereum/core/Bloom.java +++ b/rskj-core/src/main/java/org/ethereum/core/Bloom.java @@ -19,6 +19,7 @@ package org.ethereum.core; +import co.rsk.core.types.bytes.Bytes; import org.ethereum.util.ByteUtil; import java.util.Arrays; @@ -84,7 +85,7 @@ public Bloom copy() { @Override public String toString() { - return ByteUtil.toHexString(data); + return Bytes.toPrintableString(data); } @Override diff --git a/rskj-core/src/main/java/org/ethereum/core/TransactionReceipt.java b/rskj-core/src/main/java/org/ethereum/core/TransactionReceipt.java index 913c4481186..71102b8d3f3 100644 --- a/rskj-core/src/main/java/org/ethereum/core/TransactionReceipt.java +++ b/rskj-core/src/main/java/org/ethereum/core/TransactionReceipt.java @@ -19,6 +19,7 @@ package org.ethereum.core; + import co.rsk.core.types.bytes.Bytes; import org.bouncycastle.util.BigIntegers; import org.ethereum.util.*; import org.ethereum.vm.LogInfo; @@ -232,8 +233,8 @@ public String toString() { return "TransactionReceipt[" + "\n , " + (hasTxStatus() ? ("txStatus=" + (isSuccessful()? "OK" : "FAILED")) - : ("postTxState=" + ByteUtil.toHexString(postTxState))) + - "\n , cumulativeGas=" + ByteUtil.toHexString(cumulativeGas) + + : ("postTxState=" + Bytes.of(postTxState))) + + "\n , cumulativeGas=" + Bytes.of(cumulativeGas) + "\n , bloom=" + bloomFilter.toString() + "\n , logs=" + logInfoList + ']'; diff --git a/rskj-core/src/main/java/org/ethereum/core/genesis/BlockChainLoader.java b/rskj-core/src/main/java/org/ethereum/core/genesis/BlockChainLoader.java index a0805dfe01c..c14eb12e018 100644 --- a/rskj-core/src/main/java/org/ethereum/core/genesis/BlockChainLoader.java +++ b/rskj-core/src/main/java/org/ethereum/core/genesis/BlockChainLoader.java @@ -23,6 +23,7 @@ import co.rsk.core.BlockDifficulty; import co.rsk.core.bc.BlockChainImpl; import co.rsk.core.bc.BlockExecutor; +import co.rsk.core.types.bytes.Bytes; import co.rsk.db.RepositoryLocator; import co.rsk.db.StateRootHandler; import co.rsk.validators.BlockValidator; @@ -32,7 +33,6 @@ import org.ethereum.db.BlockStore; import org.ethereum.db.ReceiptStore; import org.ethereum.listener.EthereumListener; -import org.ethereum.util.ByteUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -95,7 +95,7 @@ public BlockChainImpl loadBlockchain() { logger.info("*** Loaded up to block [{}] totalDifficulty [{}] with stateRoot [{}]", bestBlock.getNumber(), totalDifficulty, - ByteUtil.toHexString(bestBlock.getStateRoot())); + Bytes.of(bestBlock.getStateRoot())); } if (!isBlockConsistent(bestBlock)) { diff --git a/rskj-core/src/main/java/org/ethereum/datasource/LevelDbDataSource.java b/rskj-core/src/main/java/org/ethereum/datasource/LevelDbDataSource.java index 29458e43b94..5897e2cdd14 100644 --- a/rskj-core/src/main/java/org/ethereum/datasource/LevelDbDataSource.java +++ b/rskj-core/src/main/java/org/ethereum/datasource/LevelDbDataSource.java @@ -19,6 +19,7 @@ package org.ethereum.datasource; +import co.rsk.core.types.bytes.Bytes; import co.rsk.metrics.profilers.Metric; import co.rsk.metrics.profilers.Profiler; import co.rsk.metrics.profilers.ProfilerFactory; @@ -140,13 +141,13 @@ public byte[] get(byte[] key) { resetDbLock.readLock().lock(); try { if (logger.isTraceEnabled()) { - logger.trace("~> LevelDbDataSource.get(): {}, key: {}", name, ByteUtil.toHexString(key)); + logger.trace("~> LevelDbDataSource.get(): {}, key: {}", name, Bytes.of(key)); } try { byte[] ret = db.get(key); if (logger.isTraceEnabled()) { - logger.trace("<~ LevelDbDataSource.get(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), (ret == null ? "null" : ret.length)); + logger.trace("<~ LevelDbDataSource.get(): {}, key: {}, return length: {}", name, Bytes.of(key), (ret == null ? "null" : ret.length)); } return ret; @@ -155,7 +156,7 @@ public byte[] get(byte[] key) { try { byte[] ret = db.get(key); if (logger.isTraceEnabled()) { - logger.trace("<~ LevelDbDataSource.get(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), (ret == null ? "null" : ret.length)); + logger.trace("<~ LevelDbDataSource.get(): {}, key: {}, return length: {}", name, Bytes.of(key), (ret == null ? "null" : ret.length)); } return ret; @@ -180,12 +181,12 @@ public byte[] put(byte[] key, byte[] value) { resetDbLock.readLock().lock(); try { if (logger.isTraceEnabled()) { - logger.trace("~> LevelDbDataSource.put(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), value.length); + logger.trace("~> LevelDbDataSource.put(): {}, key: {}, return length: {}", name, Bytes.of(key), value.length); } db.put(key, value); if (logger.isTraceEnabled()) { - logger.trace("<~ LevelDbDataSource.put(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), value.length); + logger.trace("<~ LevelDbDataSource.put(): {}, key: {}, return length: {}", name, Bytes.of(key), value.length); } return value; @@ -201,12 +202,12 @@ public void delete(byte[] key) { resetDbLock.readLock().lock(); try { if (logger.isTraceEnabled()) { - logger.trace("~> LevelDbDataSource.delete(): {}, key: {}", name, ByteUtil.toHexString(key)); + logger.trace("~> LevelDbDataSource.delete(): {}, key: {}", name, Bytes.of(key)); } db.delete(key); if (logger.isTraceEnabled()) { - logger.trace("<~ LevelDbDataSource.delete(): {}, key: {}", name, ByteUtil.toHexString(key)); + logger.trace("<~ LevelDbDataSource.delete(): {}, key: {}", name, Bytes.of(key)); } } finally { diff --git a/rskj-core/src/main/java/org/ethereum/datasource/RocksDbDataSource.java b/rskj-core/src/main/java/org/ethereum/datasource/RocksDbDataSource.java index 12567a24f92..552bc3c863f 100644 --- a/rskj-core/src/main/java/org/ethereum/datasource/RocksDbDataSource.java +++ b/rskj-core/src/main/java/org/ethereum/datasource/RocksDbDataSource.java @@ -19,6 +19,7 @@ package org.ethereum.datasource; +import co.rsk.core.types.bytes.Bytes; import co.rsk.metrics.profilers.Metric; import co.rsk.metrics.profilers.Profiler; import co.rsk.metrics.profilers.ProfilerFactory; @@ -151,13 +152,13 @@ public byte[] get(byte[] key) { while (retries < MAX_RETRIES) { try { if (logger.isTraceEnabled()) { - logger.trace("~> RocksDbDataSource.get(): {}, key: {}", name, ByteUtil.toHexString(key)); + logger.trace("~> RocksDbDataSource.get(): {}, key: {}", name, Bytes.of(key)); } byte[] ret = db.get(key); if (logger.isTraceEnabled()) { - logger.trace("<~ RocksDbDataSource.get(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), (ret == null ? "null" : ret.length)); + logger.trace("<~ RocksDbDataSource.get(): {}, key: {}, return length: {}", name, Bytes.of(key), (ret == null ? "null" : ret.length)); } result = ret; @@ -193,13 +194,13 @@ public byte[] put(byte[] key, byte[] value) { try { if (logger.isTraceEnabled()) { - logger.trace("~> RocksDbDataSource.put(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), value.length); + logger.trace("~> RocksDbDataSource.put(): {}, key: {}, return length: {}", name, Bytes.of(key), value.length); } db.put(key, value); if (logger.isTraceEnabled()) { - logger.trace("<~ RocksDbDataSource.put(): {}, key: {}, return length: {}", name, ByteUtil.toHexString(key), value.length); + logger.trace("<~ RocksDbDataSource.put(): {}, key: {}, return length: {}", name, Bytes.of(key), value.length); } } catch (RocksDBException e) { logger.error("Exception. Not retrying.", e); @@ -219,12 +220,12 @@ public void delete(byte[] key) { try { if (logger.isTraceEnabled()) { - logger.trace("~> RocksDbDataSource.delete(): {}, key: {}", name, ByteUtil.toHexString(key)); + logger.trace("~> RocksDbDataSource.delete(): {}, key: {}", name, Bytes.of(key)); } db.delete(key); if (logger.isTraceEnabled()) { - logger.trace("<~ RocksDbDataSource.delete(): {}, key: {}", name, ByteUtil.toHexString(key)); + logger.trace("<~ RocksDbDataSource.delete(): {}, key: {}", name, Bytes.of(key)); } } catch (RocksDBException e) { diff --git a/rskj-core/src/main/java/org/ethereum/db/ByteArrayWrapper.java b/rskj-core/src/main/java/org/ethereum/db/ByteArrayWrapper.java index 8e98d96b5b9..6f203681c95 100644 --- a/rskj-core/src/main/java/org/ethereum/db/ByteArrayWrapper.java +++ b/rskj-core/src/main/java/org/ethereum/db/ByteArrayWrapper.java @@ -19,6 +19,7 @@ package org.ethereum.db; +import co.rsk.core.types.bytes.Bytes; import org.ethereum.util.ByteUtil; import org.ethereum.util.FastByteComparisons; @@ -69,7 +70,7 @@ public byte[] getData() { @Override public String toString() { - return ByteUtil.toHexString(data); + return Bytes.toPrintableString(data); } public boolean equalsToByteArray(byte[] otherData) { diff --git a/rskj-core/src/main/java/org/ethereum/net/eth/message/StatusMessage.java b/rskj-core/src/main/java/org/ethereum/net/eth/message/StatusMessage.java index caafa569b30..572864bab13 100644 --- a/rskj-core/src/main/java/org/ethereum/net/eth/message/StatusMessage.java +++ b/rskj-core/src/main/java/org/ethereum/net/eth/message/StatusMessage.java @@ -19,6 +19,7 @@ package org.ethereum.net.eth.message; +import co.rsk.core.types.bytes.Bytes; import org.ethereum.util.ByteUtil; import org.ethereum.util.RLP; import org.ethereum.util.RLPList; @@ -155,9 +156,9 @@ public String toString() { return "[" + this.getCommand().name() + " protocolVersion=" + this.protocolVersion + " networkId=" + this.networkId + - " totalDifficulty=" + ByteUtil.toHexStringOrEmpty(this.totalDifficulty) + - " bestHash=" + ByteUtil.toHexString(this.bestHash) + - " genesisHash=" + ByteUtil.toHexString(this.genesisHash) + + " totalDifficulty=" + Bytes.of(this.totalDifficulty) + + " bestHash=" + Bytes.of(this.bestHash) + + " genesisHash=" + Bytes.of(this.genesisHash) + "]"; } } diff --git a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessage.java b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessage.java index 687f25965e8..d0e419ebe24 100644 --- a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessage.java +++ b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessage.java @@ -19,10 +19,10 @@ package org.ethereum.net.rlpx; +import co.rsk.core.types.bytes.Bytes; import org.bouncycastle.math.ec.ECPoint; import org.ethereum.crypto.ECKey; import org.ethereum.crypto.signature.ECDSASignature; -import org.ethereum.util.ByteUtil; import static org.bouncycastle.util.BigIntegers.asUnsignedByteArray; import static org.ethereum.util.ByteUtil.merge; @@ -121,10 +121,10 @@ public String toString() { asUnsignedByteArray(signature.getS()), new byte[]{EncryptionHandshake.recIdFromSignatureV(signature.getV())}); return "AuthInitiateMessage{" + - "\n sigBytes=" + ByteUtil.toHexString(sigBytes) + - "\n ephemeralPublicHash=" + ByteUtil.toHexString(ephemeralPublicHash) + - "\n publicKey=" + ByteUtil.toHexString(publicKey.getEncoded(false)) + - "\n nonce=" + ByteUtil.toHexString(nonce) + + "\n sigBytes=" + Bytes.of(sigBytes) + + "\n ephemeralPublicHash=" + Bytes.of(ephemeralPublicHash) + + "\n publicKey=" + Bytes.of(publicKey.getEncoded(false)) + + "\n nonce=" + Bytes.of(nonce) + "\n}"; } } diff --git a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessageV4.java b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessageV4.java index 2b35c43e3eb..861c791e0ba 100644 --- a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessageV4.java +++ b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthInitiateMessageV4.java @@ -19,6 +19,7 @@ package org.ethereum.net.rlpx; +import co.rsk.core.types.bytes.Bytes; import org.bouncycastle.math.ec.ECPoint; import org.ethereum.crypto.ECKey; import org.ethereum.crypto.signature.ECDSASignature; @@ -111,9 +112,9 @@ public String toString() { asUnsignedByteArray(signature.getS()), new byte[]{EncryptionHandshake.recIdFromSignatureV(signature.getV())}); return "AuthInitiateMessage{" + - "\n sigBytes=" + ByteUtil.toHexString(sigBytes) + - "\n publicKey=" + ByteUtil.toHexString(publicKey.getEncoded(false)) + - "\n nonce=" + ByteUtil.toHexString(nonce) + + "\n sigBytes=" + Bytes.of(sigBytes) + + "\n publicKey=" + Bytes.of(publicKey.getEncoded(false)) + + "\n nonce=" + Bytes.of(nonce) + "\n version=" + version + "\n}"; } diff --git a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessage.java b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessage.java index e1bcd67547e..0f59e3391c7 100644 --- a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessage.java +++ b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessage.java @@ -19,9 +19,9 @@ package org.ethereum.net.rlpx; +import co.rsk.core.types.bytes.Bytes; import org.bouncycastle.math.ec.ECPoint; import org.ethereum.crypto.ECKey; -import org.ethereum.util.ByteUtil; /** * Authentication response message, to be wrapped inside @@ -74,7 +74,7 @@ public byte[] encode() { public String toString() { return "AuthResponseMessage{" + "\n ephemeralPublicKey=" + ephemeralPublicKey + - "\n nonce=" + ByteUtil.toHexString(nonce) + + "\n nonce=" + Bytes.of(nonce) + "\n isTokenUsed=" + isTokenUsed + '}'; } diff --git a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessageV4.java b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessageV4.java index da57466a9eb..38772ec3dee 100644 --- a/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessageV4.java +++ b/rskj-core/src/main/java/org/ethereum/net/rlpx/AuthResponseMessageV4.java @@ -19,6 +19,7 @@ package org.ethereum.net.rlpx; +import co.rsk.core.types.bytes.Bytes; import org.bouncycastle.math.ec.ECPoint; import org.ethereum.crypto.ECKey; import org.ethereum.util.ByteUtil; @@ -74,7 +75,7 @@ public byte[] encode() { public String toString() { return "AuthResponseMessage{" + "\n ephemeralPublicKey=" + ephemeralPublicKey + - "\n nonce=" + ByteUtil.toHexString(nonce) + + "\n nonce=" + Bytes.of(nonce) + "\n version=" + version + '}'; } diff --git a/rskj-core/src/main/java/org/ethereum/net/rlpx/MessageCodec.java b/rskj-core/src/main/java/org/ethereum/net/rlpx/MessageCodec.java index 7f087ee01a4..f38432e1a2b 100644 --- a/rskj-core/src/main/java/org/ethereum/net/rlpx/MessageCodec.java +++ b/rskj-core/src/main/java/org/ethereum/net/rlpx/MessageCodec.java @@ -19,6 +19,7 @@ package org.ethereum.net.rlpx; +import co.rsk.core.types.bytes.Bytes; import com.google.common.io.ByteStreams; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageCodec; @@ -136,7 +137,7 @@ private Message decodeMessage(List frames) throws IOException { } if (loggerWire.isDebugEnabled()) { - loggerWire.debug("Recv: Encoded: {} [{}]", frameType, ByteUtil.toHexString(payload)); + loggerWire.debug("Recv: Encoded: {} [{}]", frameType, Bytes.of(payload)); } Message msg = createMessage((byte) frameType, payload); @@ -159,7 +160,7 @@ protected void encode(ChannelHandlerContext ctx, Message msg, List out) byte[] encoded = msg.getEncoded(); if (loggerWire.isDebugEnabled()) { - loggerWire.debug("Send: Encoded: {} [{}]", getCode(msg.getCommand()), ByteUtil.toHexString(encoded)); + loggerWire.debug("Send: Encoded: {} [{}]", getCode(msg.getCommand()), Bytes.of(encoded)); } List frames = splitMessageToFrames(msg); @@ -227,7 +228,7 @@ private Message createMessage(byte code, byte[] payload) { return ethMessageFactory.create(resolved, payload); } - throw new IllegalArgumentException("No such message: " + code + " [" + ByteUtil.toHexString(payload) + "]"); + throw new IllegalArgumentException("No such message: " + code + " [" + Bytes.of(payload) + "]"); } public void setChannel(Channel channel){ diff --git a/rskj-core/src/main/java/org/ethereum/net/server/PeerServerImpl.java b/rskj-core/src/main/java/org/ethereum/net/server/PeerServerImpl.java index 4cff21586ba..bfc2fdd696a 100644 --- a/rskj-core/src/main/java/org/ethereum/net/server/PeerServerImpl.java +++ b/rskj-core/src/main/java/org/ethereum/net/server/PeerServerImpl.java @@ -19,6 +19,7 @@ package org.ethereum.net.server; +import co.rsk.core.types.bytes.Bytes; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; @@ -30,7 +31,6 @@ import org.ethereum.config.SystemProperties; import org.ethereum.listener.EthereumListener; import org.ethereum.net.EthereumChannelInitializerFactory; -import org.ethereum.util.ByteUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,7 +73,7 @@ public void start() { peerServiceExecutor.execute(() -> start(config.getBindAddress(), config.getPeerPort())); } - logger.info("RskJ node started: enode://{}@{}:{}" , ByteUtil.toHexString(config.nodeId()), config.getPublicIp(), config.getPeerPort()); + logger.info("RskJ node started: enode://{}@{}:{}" , Bytes.of(config.nodeId()), config.getPublicIp(), config.getPeerPort()); } @Override @@ -110,7 +110,7 @@ private void start(InetAddress host, int port) { // Start the client. logger.info("Listening for incoming connections, host: {}, port: [{}] ", host, port); - logger.info("NodeId: [{}] ", ByteUtil.toHexString(config.nodeId())); + logger.info("NodeId: [{}] ", Bytes.of(config.nodeId())); ChannelFuture f = b.bind(host, port).sync(); diff --git a/rskj-core/src/main/java/org/ethereum/rpc/Topic.java b/rskj-core/src/main/java/org/ethereum/rpc/Topic.java index e32e591ff2c..d7f6cffc98b 100644 --- a/rskj-core/src/main/java/org/ethereum/rpc/Topic.java +++ b/rskj-core/src/main/java/org/ethereum/rpc/Topic.java @@ -18,12 +18,11 @@ package org.ethereum.rpc; -import java.util.Arrays; - -import org.ethereum.util.ByteUtil; - +import co.rsk.core.types.bytes.Bytes; import co.rsk.util.HexUtils; +import java.util.Arrays; + /** * Created by ajlopez on 18/01/2018. */ @@ -79,7 +78,7 @@ public int hashCode() { @Override public String toString() { - return ByteUtil.toHexString(bytes); + return Bytes.toPrintableString(bytes); } public String toJsonString() { diff --git a/rskj-core/src/main/java/org/ethereum/solidity/SolidityType.java b/rskj-core/src/main/java/org/ethereum/solidity/SolidityType.java index ea0b8a2dfff..a4ef7aa34be 100644 --- a/rskj-core/src/main/java/org/ethereum/solidity/SolidityType.java +++ b/rskj-core/src/main/java/org/ethereum/solidity/SolidityType.java @@ -19,6 +19,7 @@ package org.ethereum.solidity; +import co.rsk.core.types.bytes.Bytes; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; import org.ethereum.util.ByteUtil; @@ -375,7 +376,7 @@ public byte[] encode(Object value) { byte[] addr = super.encode(value); for (int i = 0; i < 12; i++) { if (addr[i] != 0) { - throw new RuntimeException("Invalid address (should be 20 bytes length): " + ByteUtil.toHexString(addr)); + throw new RuntimeException("Invalid address (should be 20 bytes length): " + Bytes.of(addr)); } } return addr; diff --git a/rskj-core/src/main/java/org/ethereum/vm/VM.java b/rskj-core/src/main/java/org/ethereum/vm/VM.java index f7568f1f067..2f829c8b426 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/VM.java +++ b/rskj-core/src/main/java/org/ethereum/vm/VM.java @@ -21,6 +21,7 @@ import co.rsk.config.VmConfig; import co.rsk.core.RskAddress; +import co.rsk.core.types.bytes.Bytes; import co.rsk.crypto.Keccak256; import co.rsk.rpc.netty.ExecTimeoutContext; import org.bouncycastle.util.BigIntegers; @@ -2175,8 +2176,8 @@ private void dumpLine(OpCode op, long gasBefore, long gasCost, long memWords, Pr DataWord key = keysIterator.next(); DataWord value = storage.getStorageValue(ownerAddress, key); dumpLogger.trace("{} {}", - ByteUtil.toHexString(key.getNoLeadZeroesData()), - ByteUtil.toHexString(value.getNoLeadZeroesData())); + Bytes.of(key.getNoLeadZeroesData()), + Bytes.of(value.getNoLeadZeroesData())); } break; default: diff --git a/rskj-core/src/main/java/org/ethereum/vm/program/Program.java b/rskj-core/src/main/java/org/ethereum/vm/program/Program.java index 1fb34df8b82..33ef0607727 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/program/Program.java +++ b/rskj-core/src/main/java/org/ethereum/vm/program/Program.java @@ -21,6 +21,7 @@ import co.rsk.config.VmConfig; import co.rsk.core.Coin; import co.rsk.core.RskAddress; +import co.rsk.core.types.bytes.Bytes; import co.rsk.crypto.Keccak256; import co.rsk.pcc.NativeContract; import co.rsk.peg.Bridge; @@ -581,7 +582,7 @@ private void refundRemainingGas(long gasLimit, ProgramResult programResult) { refundGas(refundGas, "remaining gas from the internal call"); if (isGasLogEnabled) { gasLogger.info("The remaining gas is refunded, account: [{}], gas: [{}] ", - ByteUtil.toHexString(getOwnerAddress().getLast20Bytes()), + Bytes.of(getOwnerAddress().getLast20Bytes()), refundGas ); } diff --git a/rskj-core/src/main/java/org/ethereum/vm/program/invoke/ProgramInvokeFactoryImpl.java b/rskj-core/src/main/java/org/ethereum/vm/program/invoke/ProgramInvokeFactoryImpl.java index 286c2662b19..258c3ecf416 100644 --- a/rskj-core/src/main/java/org/ethereum/vm/program/invoke/ProgramInvokeFactoryImpl.java +++ b/rskj-core/src/main/java/org/ethereum/vm/program/invoke/ProgramInvokeFactoryImpl.java @@ -20,6 +20,7 @@ import co.rsk.core.Coin; import co.rsk.core.RskAddress; +import co.rsk.core.types.bytes.Bytes; import org.ethereum.core.Block; import org.ethereum.core.Repository; import org.ethereum.core.SignatureCache; @@ -118,19 +119,19 @@ public ProgramInvoke createProgramInvoke(Transaction tx, int txindex, Block bloc "minimumGasPrice={}\n", addr, - ByteUtil.toHexString(origin), - ByteUtil.toHexString(caller), + Bytes.of(origin), + Bytes.of(caller), balance, txGasPrice, new BigInteger(1, gas).longValue(), callValue, - ByteUtil.toHexString(data), - ByteUtil.toHexString(lastHash), - ByteUtil.toHexString(coinbase), + Bytes.of(data), + Bytes.of(lastHash), + Bytes.of(coinbase), timestamp, number, txindex, - ByteUtil.toHexString(difficulty), + Bytes.of(difficulty), gaslimit, minimumGasPrice); } @@ -190,20 +191,20 @@ public ProgramInvoke createProgramInvoke(Program program, DataWord toAddress, Da "difficulty={}\n" + "gaslimit={}\n" + "minimumGasPrice={}\n", - ByteUtil.toHexString(address.getLast20Bytes()), - ByteUtil.toHexString(origin.getLast20Bytes()), - ByteUtil.toHexString(caller.getLast20Bytes()), + Bytes.of(address.getLast20Bytes()), + Bytes.of(origin.getLast20Bytes()), + Bytes.of(caller.getLast20Bytes()), balance.toString(), txGasPrice.longValue(), agas, - ByteUtil.toHexString(callValue.getNoLeadZeroesData()), + Bytes.of(callValue.getNoLeadZeroesData()), data == null ? "" : ByteUtil.toHexString(data), - ByteUtil.toHexString(lastHash.getData()), - ByteUtil.toHexString(coinbase.getLast20Bytes()), + Bytes.of(lastHash.getData()), + Bytes.of(coinbase.getLast20Bytes()), timestamp.longValue(), number.longValue(), transactionIndex.intValue(), - ByteUtil.toHexString(difficulty.getNoLeadZeroesData()), + Bytes.of(difficulty.getNoLeadZeroesData()), gasLimit.bigIntValue(), minimumGasPrice.longValue()); } diff --git a/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java b/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java index ba09d62c288..b3e7fc6c216 100644 --- a/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java +++ b/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java @@ -79,7 +79,7 @@ void validatesExtendedPublicKeyFormat() { }); Assertions.fail(); } catch (NativeContractIllegalArgumentException e) { - Assertions.assertTrue(e.getMessage().contains("Invalid extended public key")); + Assertions.assertEquals("Invalid extended public key 'this-is-not-an-xpub'", e.getMessage()); } } @@ -91,7 +91,7 @@ void failsUponInvalidPublicKey() { }); Assertions.fail(); } catch (NativeContractIllegalArgumentException e) { - Assertions.assertTrue(e.getMessage().contains("Invalid extended public key")); + Assertions.assertEquals("Invalid extended public key 'tpubD6NzVbkrYhZ4YHQqwWz3Tm1ESZ9A...'", e.getMessage()); } } @@ -101,7 +101,7 @@ void failsUponNull() { method.execute(null); Assertions.fail(); } catch (NativeContractIllegalArgumentException e) { - Assertions.assertTrue(e.getMessage().contains("Invalid extended public key")); + Assertions.assertEquals("Invalid extended public key 'null'", e.getMessage()); } } diff --git a/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java b/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java index 2e4dbad3eb4..57b90d4a84a 100644 --- a/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java +++ b/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java @@ -25,6 +25,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + class HDWalletUtilsHelperTest { private HDWalletUtilsHelper helper; @@ -35,7 +37,7 @@ void createHelper() { @Test void validateAndExtractNetworkFromExtendedPublicKeyMainnet() throws NativeContractIllegalArgumentException { - Assertions.assertEquals( + assertEquals( NetworkParameters.fromID(NetworkParameters.ID_MAINNET), helper.validateAndExtractNetworkFromExtendedPublicKey("xpubSomethingSomething") ); @@ -43,14 +45,25 @@ void validateAndExtractNetworkFromExtendedPublicKeyMainnet() throws NativeContra @Test void validateAndExtractNetworkFromExtendedPublicKeyTestnet() throws NativeContractIllegalArgumentException { - Assertions.assertEquals( + assertEquals( NetworkParameters.fromID(NetworkParameters.ID_TESTNET), helper.validateAndExtractNetworkFromExtendedPublicKey("tpubSomethingSomething") ); } @Test - void validateAndExtractNetworkFromExtendedPublicKeyInvalid() { - Assertions.assertThrows(NativeContractIllegalArgumentException.class, () -> helper.validateAndExtractNetworkFromExtendedPublicKey("completelyInvalidStuff")); + void validateAndExtractNetworkFromExtendedPublicKeyWithInvalidXpub() { + NativeContractIllegalArgumentException exception = Assertions.assertThrows( + NativeContractIllegalArgumentException.class, + () -> helper.validateAndExtractNetworkFromExtendedPublicKey("completelyInvalidStuff")); + assertEquals("Invalid extended public key 'completelyInvalidStuff'", exception.getMessage()); + } + + @Test + void validateAndExtractNetworkFromExtendedPublicKeyWithInvalidLongXpub() { + NativeContractIllegalArgumentException exception = Assertions.assertThrows( + NativeContractIllegalArgumentException.class, + () -> helper.validateAndExtractNetworkFromExtendedPublicKey("completelyInvalidLongLongLonStuff")); + assertEquals("Invalid extended public key 'completelyInvalidLongLongLonStuf...'", exception.getMessage()); } } diff --git a/rskj-core/src/test/java/co/rsk/util/BytesTest.java b/rskj-core/src/test/java/co/rsk/util/BytesTest.java new file mode 100644 index 00000000000..f16957ee6df --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/util/BytesTest.java @@ -0,0 +1,76 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * (derived from ethereumJ library, Copyright (c) 2016 ) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.util; + +import co.rsk.core.types.bytes.Bytes; +import org.ethereum.TestUtils; +import org.ethereum.util.ByteUtil; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class BytesTest { + + @Test + void testBytesToString() { + byte[] bArray = new byte[]{1, 2, 3, 5, 8, 13}; + String actualMessage = String.format("Some %s hex", Bytes.of(bArray)); + String expectedMessage = "Some " + ByteUtil.toHexString(bArray) + " hex"; + + assertEquals(expectedMessage, actualMessage); + } + + @Test + void testShortEnoughBytesToString() { + byte[] bArray = TestUtils.generateBytes("hash",32); + + String actualMessage = String.format("Some %s hex", Bytes.of(bArray)); + String expectedMessage = "Some " + ByteUtil.toHexString(bArray) + " hex"; + + assertEquals(expectedMessage, actualMessage); + } + + @Test + void testLongBytesToString() { + byte[] bArray1 = TestUtils.generateBytes("hash1",15); + byte[] bArray2 = TestUtils.generateBytes("hash2",15); + byte[] finalArray = ByteUtil.merge(bArray1, new byte[]{1, 2, 3}, bArray2); + + assertEquals(33, finalArray.length); + + String actualMessage = String.format("Some %s hex", Bytes.of(finalArray)); + String expectedMessage = "Some " + + ByteUtil.toHexString(bArray1) + + ".." + + ByteUtil.toHexString(bArray2) + + " hex"; + + assertEquals(expectedMessage, actualMessage); + } + + @Test + void testNullBytesToString() { + byte[] bArray = null; + String actualMessage = String.format("Some %s hex", Bytes.of(bArray)); + String expectedMessage = "Some " + null + " hex"; + + assertEquals(expectedMessage, actualMessage); + } +} diff --git a/rskj-core/src/test/java/org/ethereum/core/BloomTest.java b/rskj-core/src/test/java/org/ethereum/core/BloomTest.java index fc09358c9ab..798775ba7e7 100644 --- a/rskj-core/src/test/java/org/ethereum/core/BloomTest.java +++ b/rskj-core/src/test/java/org/ethereum/core/BloomTest.java @@ -19,6 +19,7 @@ package org.ethereum.core; +import co.rsk.core.types.bytes.Bytes; import org.ethereum.crypto.HashUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -30,10 +31,8 @@ */ class BloomTest { - @Test /// based on http://bit.ly/1MtXxFg - void test1(){ - + void test1() { byte[] address = Hex.decode("095e7baea6a6c7c4c2dfeb977efac326af552d87"); Bloom addressBloom = Bloom.create(HashUtil.keccak256(address)); @@ -44,10 +43,9 @@ void test1(){ totalBloom.or(addressBloom); totalBloom.or(topicBloom); - Assertions.assertEquals( "00000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000040000000000000000000000000000000000000000000000000000000", - totalBloom.toString() + Bytes.of(totalBloom.getData()).toHexString() ); } From 1cb876069e0f2f2f16ca1363e638e69fb6f1c375 Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Mon, 1 Jul 2024 17:41:49 +0300 Subject: [PATCH 17/20] chore(logging): add a bit of unit tests --- .../java/co/rsk/core/types/bytes/Bytes.java | 16 +++- .../co/rsk/core/types/bytes/BytesSlice.java | 12 ++- .../core/types/bytes/HexPrintableBytes.java | 2 +- .../java/co/rsk/peg/bitcoin/UtxoUtils.java | 2 +- .../rsk/core/types/bytes/BytesSliceTest.java | 77 +++++++++++++++++++ .../{util => core/types/bytes}/BytesTest.java | 67 +++++++++++++--- 6 files changed, 157 insertions(+), 19 deletions(-) create mode 100644 rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java rename rskj-core/src/test/java/co/rsk/{util => core/types/bytes}/BytesTest.java (51%) diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java index dd29eb55ee5..ce988888068 100644 --- a/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java +++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/Bytes.java @@ -58,15 +58,25 @@ static Bytes of(@Nullable byte[] unsafeByteArray) { /** * A helper method for printing "nullable" byte arrays. * - * @return {@code null}, if {@code byteArray} is {@code null}. Otherwise - {@code Bytes.of(byteArray).toPrintableString()}. + * @return {@code valueIfNull}, if {@code byteArray} is {@code null}. Otherwise - {@code Bytes.of(byteArray).toPrintableString()}. */ - static String toPrintableString(@Nullable byte[] byteArray) { + static String toPrintableString(@Nullable byte[] byteArray, @Nullable String valueIfNull) { if (byteArray == null) { - return null; + return valueIfNull; } return of(byteArray).toPrintableString(); } + /** + * A helper method for printing "nullable" byte arrays. + * + * @return {@code ""}, if {@code byteArray} is {@code null}. Otherwise - {@code Bytes.of(byteArray).toPrintableString()}. + */ + @Nonnull + static String toPrintableString(@Nullable byte[] byteArray) { + return toPrintableString(byteArray, ""); + } + /** * A helper method for extracting "unsafe" underlying byte array from the {@code bytes} instance. * diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java index a91fde0b7f4..5210ff8eea0 100644 --- a/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java +++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/BytesSlice.java @@ -49,10 +49,18 @@ public interface BytesSlice extends HexPrintableBytes { */ byte[] copyArrayOfRange(int from, int to); + default byte[] copyArray() { + return copyArrayOfRange(0, length()); + } + default Bytes copyBytesOfRange(int from, int to) { return Bytes.of(copyArrayOfRange(from, to)); } + default Bytes copyBytes() { + return Bytes.of(copyArrayOfRange(0, length())); + } + default BytesSlice slice(int from, int to) { return new BytesSliceImpl(this, from, to); } @@ -71,7 +79,7 @@ class BytesSliceImpl implements BytesSlice { if (from < 0) { throw new IndexOutOfBoundsException(from + " < " + 0); } - if (from >= to) { + if (from > to) { throw new IndexOutOfBoundsException(from + " > " + to); } if (to > originBytes.length()) { @@ -97,7 +105,7 @@ public byte byteAt(int index) { @Override public byte[] copyArrayOfRange(int from, int to) { - if (from < 0 || from >= to || to > length()) { + if (from < 0 || from > to || to > length()) { throw new IndexOutOfBoundsException("invalid 'from' and/or 'to': [" + from + ";" + to + ")"); } return originBytes.copyArrayOfRange(this.from + from, this.from + to); diff --git a/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java b/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java index 0eeeebd329c..d700c0cc6a6 100644 --- a/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java +++ b/rskj-core/src/main/java/co/rsk/core/types/bytes/HexPrintableBytes.java @@ -50,7 +50,7 @@ default String toPrintableString(@Nonnull Formatter formatter } default String toPrintableString(@Nonnull Formatter formatter) { - return formatter.toFormattedString(this, 0, length()); + return toPrintableString(formatter, 0, length()); } @Override diff --git a/rskj-core/src/main/java/co/rsk/peg/bitcoin/UtxoUtils.java b/rskj-core/src/main/java/co/rsk/peg/bitcoin/UtxoUtils.java index 6177264287d..2adf53a0913 100644 --- a/rskj-core/src/main/java/co/rsk/peg/bitcoin/UtxoUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/bitcoin/UtxoUtils.java @@ -40,7 +40,7 @@ public static List decodeOutpointValues(byte[] encodedOutpointValues) { } catch (Exception ex) { throw new InvalidOutpointValueException( String.format("Invalid value with invalid VarInt format: %s", - Bytes.of(encodedOutpointValues).toPrintableString().toUpperCase() + Bytes.toPrintableString(encodedOutpointValues).toUpperCase() ), ex ); diff --git a/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java new file mode 100644 index 00000000000..93707953604 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesSliceTest.java @@ -0,0 +1,77 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * (derived from ethereumJ library, Copyright (c) 2016 ) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.core.types.bytes; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class BytesSliceTest { + + @Test + void testCopyArrayOfRange() { + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; + byte[] expectedResult = new byte[]{3, 4, 5}; + assertArrayEquals(expectedResult, Bytes.of(bArray).slice(0, bArray.length).copyArrayOfRange(2, 5)); + } + + @Test + void testCopyArray() { + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; + byte[] expectedResult = new byte[]{3, 4, 5}; + byte[] actualResult = Bytes.of(bArray).slice(2, 5).copyArray(); + assertNotSame(expectedResult, actualResult); // refs are different + assertArrayEquals(expectedResult, actualResult); + } + + @Test + void testCopyBytesOfRange() { + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; + Bytes expectedResult = Bytes.of(new byte[]{3, 4, 5}); + assertTrue(Bytes.equalBytes(expectedResult, Bytes.of(bArray).slice(0, bArray.length).copyBytesOfRange(2, 5))); + } + + @Test + void testCopyBytes() { + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; + Bytes expectedResult = Bytes.of(new byte[]{3, 4, 5}); + Bytes actualResult = Bytes.of(bArray).slice(2, 5).copyBytes(); + assertTrue(Bytes.equalBytes(expectedResult, actualResult)); + assertArrayEquals(expectedResult.asUnsafeByteArray(), actualResult.asUnsafeByteArray()); + } + + @Test + void testSlice() { + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; + BytesSlice actualResult = Bytes.of(bArray).slice(1, 6).slice(1, 4).slice(1, 3); + byte[] expectedResult = new byte[]{4, 5}; + assertEquals(2, actualResult.length()); + assertArrayEquals(expectedResult, actualResult.copyArray()); + } + + @Test + void testEmptySlice() { + byte[] bArray = new byte[]{1, 2, 3, 4, 5, 6}; + BytesSlice actualResult = Bytes.of(bArray).slice(1, 6).slice(1, 4).slice(1, 3).slice(0, 0); + byte[] expectedResult = new byte[]{}; + assertEquals(0, actualResult.length()); + assertArrayEquals(expectedResult, actualResult.copyArray()); + } +} diff --git a/rskj-core/src/test/java/co/rsk/util/BytesTest.java b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java similarity index 51% rename from rskj-core/src/test/java/co/rsk/util/BytesTest.java rename to rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java index f16957ee6df..b60ca431ddc 100644 --- a/rskj-core/src/test/java/co/rsk/util/BytesTest.java +++ b/rskj-core/src/test/java/co/rsk/core/types/bytes/BytesTest.java @@ -17,9 +17,8 @@ * along with this program. If not, see . */ -package co.rsk.util; +package co.rsk.core.types.bytes; -import co.rsk.core.types.bytes.Bytes; import org.ethereum.TestUtils; import org.ethereum.util.ByteUtil; import org.junit.jupiter.api.Test; @@ -28,11 +27,46 @@ class BytesTest { + @Test + void testBytesOf() { + assertNull(Bytes.of(null)); + assertNotNull(Bytes.of(new byte[]{})); + assertNotNull(Bytes.of(new byte[]{1})); + } + + @Test + void testToPrintableString() { + assertEquals("0a", Bytes.toPrintableString(new byte[]{10})); + } + + @Test + void testToPrintableStringWithNull() { + assertEquals("", Bytes.toPrintableString((byte[]) null)); + } + + @Test + void testToPrintableStringWithDefaultValue() { + assertEquals("xyz", Bytes.toPrintableString(null, "xyz")); + } + + @Test + void testAsUnsafeByteArray() { + byte[] bArray = {1, 2, 3}; + assertTrue(bArray == Bytes.of(bArray).asUnsafeByteArray()); + } + + @Test + void testEqualBytes() { + byte[] b1Array = {1, 2, 3}; + byte[] b2Array = {1, 2, 3}; + assertTrue(Bytes.equalBytes(Bytes.of(b1Array), Bytes.of(b2Array))); + } + @Test void testBytesToString() { byte[] bArray = new byte[]{1, 2, 3, 5, 8, 13}; - String actualMessage = String.format("Some %s hex", Bytes.of(bArray)); - String expectedMessage = "Some " + ByteUtil.toHexString(bArray) + " hex"; + String actualMessage = String.format("Some '%s' hex", Bytes.of(bArray)); + String expectedMessage = "Some '" + ByteUtil.toHexString(bArray) + "' hex"; assertEquals(expectedMessage, actualMessage); } @@ -41,8 +75,8 @@ void testBytesToString() { void testShortEnoughBytesToString() { byte[] bArray = TestUtils.generateBytes("hash",32); - String actualMessage = String.format("Some %s hex", Bytes.of(bArray)); - String expectedMessage = "Some " + ByteUtil.toHexString(bArray) + " hex"; + String actualMessage = String.format("Some '%s' hex", Bytes.of(bArray)); + String expectedMessage = "Some '" + ByteUtil.toHexString(bArray) + "' hex"; assertEquals(expectedMessage, actualMessage); } @@ -55,12 +89,12 @@ void testLongBytesToString() { assertEquals(33, finalArray.length); - String actualMessage = String.format("Some %s hex", Bytes.of(finalArray)); - String expectedMessage = "Some " + String actualMessage = String.format("Some '%s' hex", Bytes.of(finalArray)); + String expectedMessage = "Some '" + ByteUtil.toHexString(bArray1) + ".." + ByteUtil.toHexString(bArray2) - + " hex"; + + "' hex"; assertEquals(expectedMessage, actualMessage); } @@ -68,9 +102,18 @@ void testLongBytesToString() { @Test void testNullBytesToString() { byte[] bArray = null; - String actualMessage = String.format("Some %s hex", Bytes.of(bArray)); - String expectedMessage = "Some " + null + " hex"; + String actualMessage = String.format("Some '%s' hex", Bytes.of(bArray)); + String expectedMessage = "Some '" + null + "' hex"; + + assertEquals(expectedMessage, actualMessage); + } + + @Test + void testEmptyBytesToString() { + byte[] bArray = new byte[]{}; + String actualMessage = String.format("Some '%s' hex", Bytes.of(bArray)); + String expectedMessage = "Some '' hex"; assertEquals(expectedMessage, actualMessage); } -} +} \ No newline at end of file From edb71a0898669c9a6a9a2ce3a915b9f3764d0bcb Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Mon, 1 Jul 2024 19:39:40 +0300 Subject: [PATCH 18/20] chore(logging): change StringUtils.DEFAULT_MAX_LEN to 64; add tests --- .../main/java/co/rsk/util/StringUtils.java | 2 +- .../java/co/rsk/util/StringUtilsTest.java | 55 +++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 rskj-core/src/test/java/co/rsk/util/StringUtilsTest.java diff --git a/rskj-core/src/main/java/co/rsk/util/StringUtils.java b/rskj-core/src/main/java/co/rsk/util/StringUtils.java index 7f6019d082e..a7c58a322b3 100644 --- a/rskj-core/src/main/java/co/rsk/util/StringUtils.java +++ b/rskj-core/src/main/java/co/rsk/util/StringUtils.java @@ -22,7 +22,7 @@ public class StringUtils { - private static final int DEFAULT_MAX_LEN = 32; + private static final int DEFAULT_MAX_LEN = 64; public static String trim(@Nullable String src) { return trim(src, DEFAULT_MAX_LEN); diff --git a/rskj-core/src/test/java/co/rsk/util/StringUtilsTest.java b/rskj-core/src/test/java/co/rsk/util/StringUtilsTest.java new file mode 100644 index 00000000000..2cd58093e6f --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/util/StringUtilsTest.java @@ -0,0 +1,55 @@ +/* + * This file is part of RskJ + * Copyright (C) 2024 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.util; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class StringUtilsTest { + + private static final String STR_64_CHARS = "ee5c851e70650111887bb6c04e18ef4353391abe37846234c17895a9ca2b33d5"; + private static final String STR_65_CHARS = STR_64_CHARS + "a"; + + @Test + void testTrim() { + assertNull(StringUtils.trim(null)); + assertEquals("", StringUtils.trim("")); + assertEquals("a", StringUtils.trim("a")); + + assertEquals(64, STR_64_CHARS.length()); + assertEquals(65, STR_65_CHARS.length()); + + assertEquals(STR_64_CHARS, StringUtils.trim(STR_64_CHARS)); + assertEquals(STR_64_CHARS + "...", StringUtils.trim(STR_65_CHARS)); + } + + @Test + void testTrimWithMaxLength() { + assertEquals("...", StringUtils.trim("abc", 0)); + assertEquals("abc", StringUtils.trim("abc", 3)); + assertEquals("abc", StringUtils.trim("abc", 4)); + assertEquals("abc...", StringUtils.trim("abcd", 3)); + } + + @Test + void testTrimWithInvalidMaxLength() { + assertThrows(IllegalArgumentException.class, () -> StringUtils.trim("abc", -1)); + } +} From f45b98749d708e97cef9fbd48e07198965cece7b Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Thu, 4 Jul 2024 18:44:01 +0300 Subject: [PATCH 19/20] chore(logging): fix broken tests --- .../pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java | 2 +- .../src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java b/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java index b3e7fc6c216..1fbe8101c0b 100644 --- a/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java +++ b/rskj-core/src/test/java/co/rsk/pcc/bto/ExtractPublicKeyFromExtendedPublicKeyTest.java @@ -91,7 +91,7 @@ void failsUponInvalidPublicKey() { }); Assertions.fail(); } catch (NativeContractIllegalArgumentException e) { - Assertions.assertEquals("Invalid extended public key 'tpubD6NzVbkrYhZ4YHQqwWz3Tm1ESZ9A...'", e.getMessage()); + Assertions.assertEquals("Invalid extended public key 'tpubD6NzVbkrYhZ4YHQqwWz3Tm1ESZ9AidobeyLG4mEezB6hN8gFFWrcjczyF77L...'", e.getMessage()); } } diff --git a/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java b/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java index 57b90d4a84a..7722487229c 100644 --- a/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java +++ b/rskj-core/src/test/java/co/rsk/pcc/bto/HDWalletUtilsHelperTest.java @@ -63,7 +63,7 @@ void validateAndExtractNetworkFromExtendedPublicKeyWithInvalidXpub() { void validateAndExtractNetworkFromExtendedPublicKeyWithInvalidLongXpub() { NativeContractIllegalArgumentException exception = Assertions.assertThrows( NativeContractIllegalArgumentException.class, - () -> helper.validateAndExtractNetworkFromExtendedPublicKey("completelyInvalidLongLongLonStuff")); - assertEquals("Invalid extended public key 'completelyInvalidLongLongLonStuf...'", exception.getMessage()); + () -> helper.validateAndExtractNetworkFromExtendedPublicKey("completelyInvalidLongLongLongLongLongLongLongLongLongLongLonStuff")); + assertEquals("Invalid extended public key 'completelyInvalidLongLongLongLongLongLongLongLongLongLongLonStuf...'", exception.getMessage()); } } From f582ac4ab7b5c2ca8b8cf3d15bb061ac7e64227e Mon Sep 17 00:00:00 2001 From: Volodymyr Kravets Date: Wed, 10 Jul 2024 10:58:14 +0300 Subject: [PATCH 20/20] Changed modifier to ARROWHEAD for v6.3.1 --- rskj-core/src/main/resources/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rskj-core/src/main/resources/version.properties b/rskj-core/src/main/resources/version.properties index da76564f104..f055a4c4135 100644 --- a/rskj-core/src/main/resources/version.properties +++ b/rskj-core/src/main/resources/version.properties @@ -1,2 +1,2 @@ versionNumber='6.3.1' -modifier="RC" +modifier="ARROWHEAD"