From 252818065000110d1c75a81aadb6ffbf2d6a39f2 Mon Sep 17 00:00:00 2001 From: Iago Lluque Date: Fri, 29 Jul 2022 12:45:47 +0200 Subject: [PATCH] Added option to set signature fields to 0x0 for Remasc on RPC response --- .../co/rsk/config/RskSystemProperties.java | 6 +- .../main/java/org/ethereum/rpc/Web3Impl.java | 10 +-- .../org/ethereum/rpc/dto/BlockResultDTO.java | 33 ++++---- .../rpc/dto/TransactionResultDTO.java | 20 +++-- rskj-core/src/main/resources/expected.conf | 1 + rskj-core/src/main/resources/reference.conf | 6 +- .../ethereum/rpc/dto/BlockResultDTOTest.java | 75 ++++++++++++------- .../rpc/dto/TransactionResultDTOTest.java | 31 ++++++-- 8 files changed, 119 insertions(+), 63 deletions(-) diff --git a/rskj-core/src/main/java/co/rsk/config/RskSystemProperties.java b/rskj-core/src/main/java/co/rsk/config/RskSystemProperties.java index ca4ec2a0051..4bc779f910d 100644 --- a/rskj-core/src/main/java/co/rsk/config/RskSystemProperties.java +++ b/rskj-core/src/main/java/co/rsk/config/RskSystemProperties.java @@ -146,7 +146,7 @@ public long workSubmissionRateLimitInMills() { public boolean updateWorkOnNewTransaction() { return getBoolean("miner.server.updateWorkOnNewTransaction", false); } - + public long minerMinGasPrice() { return configFromFiles.getLong("miner.minGasPrice"); } @@ -414,4 +414,8 @@ public boolean fastBlockPropagation() { public Integer getMessageQueueMaxSize() { return configFromFiles.getInt("peer.messageQueue.maxSizePerPeer"); } + + public boolean rpcZeroSignatureIfRemasc() { + return configFromFiles.getBoolean("rpc.zeroSignatureIfRemasc"); + } } diff --git a/rskj-core/src/main/java/org/ethereum/rpc/Web3Impl.java b/rskj-core/src/main/java/org/ethereum/rpc/Web3Impl.java index 941af56c723..43fc5432101 100644 --- a/rskj-core/src/main/java/org/ethereum/rpc/Web3Impl.java +++ b/rskj-core/src/main/java/org/ethereum/rpc/Web3Impl.java @@ -637,7 +637,7 @@ public BlockInformationResult getBlockInformationResult(BlockInformation blockIn } public BlockResultDTO getBlockResult(Block b, boolean fullTx) { - return BlockResultDTO.fromBlock(b, fullTx, this.blockStore, config.skipRemasc()); + return BlockResultDTO.fromBlock(b, fullTx, this.blockStore, config.skipRemasc(), config.rpcZeroSignatureIfRemasc()); } public BlockInformationResult[] eth_getBlocksByNumber(String number) { @@ -705,7 +705,7 @@ public TransactionResultDTO eth_getTransactionByHash(String transactionHash) { for (Transaction tx : txs) { if (tx.getHash().equals(txHash)) { - return s = new TransactionResultDTO(null, null, tx); + return s = new TransactionResultDTO(null, null, tx, config.rpcZeroSignatureIfRemasc()); } } } else { @@ -722,7 +722,7 @@ public TransactionResultDTO eth_getTransactionByHash(String transactionHash) { return null; } - return s = new TransactionResultDTO(block, txInfo.getIndex(), txInfo.getReceipt().getTransaction()); + return s = new TransactionResultDTO(block, txInfo.getIndex(), txInfo.getReceipt().getTransaction(), config.rpcZeroSignatureIfRemasc()); } finally { logger.debug("eth_getTransactionByHash({}): {}", transactionHash, s); } @@ -746,7 +746,7 @@ public TransactionResultDTO eth_getTransactionByBlockHashAndIndex(String blockHa Transaction tx = b.getTransactionsList().get(idx); - return s = new TransactionResultDTO(b, idx, tx); + return s = new TransactionResultDTO(b, idx, tx, config.rpcZeroSignatureIfRemasc()); } finally { if (logger.isDebugEnabled()) { logger.debug("eth_getTransactionByBlockHashAndIndex({}, {}): {}", blockHash, index, s); @@ -769,7 +769,7 @@ public TransactionResultDTO eth_getTransactionByBlockNumberAndIndex(String bnOrI return null; } - s = new TransactionResultDTO(block.get(), idx, txs.get(idx)); + s = new TransactionResultDTO(block.get(), idx, txs.get(idx), config.rpcZeroSignatureIfRemasc()); return s; } finally { if (logger.isDebugEnabled()) { diff --git a/rskj-core/src/main/java/org/ethereum/rpc/dto/BlockResultDTO.java b/rskj-core/src/main/java/org/ethereum/rpc/dto/BlockResultDTO.java index b6e47d304d3..e6f33497eda 100644 --- a/rskj-core/src/main/java/org/ethereum/rpc/dto/BlockResultDTO.java +++ b/rskj-core/src/main/java/org/ethereum/rpc/dto/BlockResultDTO.java @@ -18,7 +18,15 @@ package org.ethereum.rpc.dto; -import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH; +import co.rsk.core.BlockDifficulty; +import co.rsk.core.Coin; +import co.rsk.core.RskAddress; +import co.rsk.crypto.Keccak256; +import co.rsk.util.HexUtils; +import org.ethereum.core.Block; +import org.ethereum.core.BlockHeader; +import org.ethereum.core.Transaction; +import org.ethereum.db.BlockStore; import java.util.ArrayList; import java.util.Collections; @@ -27,16 +35,7 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; -import org.ethereum.core.Block; -import org.ethereum.core.BlockHeader; -import org.ethereum.core.Transaction; -import org.ethereum.db.BlockStore; - -import co.rsk.core.BlockDifficulty; -import co.rsk.core.Coin; -import co.rsk.core.RskAddress; -import co.rsk.crypto.Keccak256; -import co.rsk.util.HexUtils; +import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH; public class BlockResultDTO { @@ -123,7 +122,7 @@ private BlockResultDTO( this.paidFees = paidFees != null ? HexUtils.toQuantityJsonHex(paidFees.getBytes()) : null; } - public static BlockResultDTO fromBlock(Block b, boolean fullTx, BlockStore blockStore, boolean skipRemasc) { + public static BlockResultDTO fromBlock(Block b, boolean fullTx, BlockStore blockStore, boolean skipRemasc, boolean zeroSignatureIfRemasc) { if (b == null) { return null; } @@ -136,7 +135,7 @@ public static BlockResultDTO fromBlock(Block b, boolean fullTx, BlockStore block List blockTransactions = b.getTransactionsList(); // For full tx will present as TransactionResultDTO otherwise just as transaction hash List transactions = IntStream.range(0, blockTransactions.size()) - .mapToObj(txIndex -> toTransactionResult(txIndex, b, fullTx, skipRemasc)) + .mapToObj(txIndex -> toTransactionResult(txIndex, b, fullTx, skipRemasc, zeroSignatureIfRemasc)) .filter(Objects::nonNull) .collect(Collectors.toList()); @@ -182,15 +181,15 @@ public static BlockResultDTO fromBlock(Block b, boolean fullTx, BlockStore block ); } - private static Object toTransactionResult(int transactionIndex, Block block, boolean fullTx, boolean skipRemasc) { + private static Object toTransactionResult(int transactionIndex, Block block, boolean fullTx, boolean skipRemasc, boolean zeroSignatureIfRemasc) { Transaction transaction = block.getTransactionsList().get(transactionIndex); if(skipRemasc && transaction.isRemascTransaction(transactionIndex, block.getTransactionsList().size())) { return null; } - + if(fullTx) { - return new TransactionResultDTO(block, transactionIndex, transaction); + return new TransactionResultDTO(block, transactionIndex, transaction, zeroSignatureIfRemasc); } return transaction.getHash().toJsonString(); @@ -291,4 +290,4 @@ public String getHashForMergedMining() { public String getPaidFees() { return paidFees; } -} \ No newline at end of file +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/dto/TransactionResultDTO.java b/rskj-core/src/main/java/org/ethereum/rpc/dto/TransactionResultDTO.java index e7469ed4567..c86003493f9 100644 --- a/rskj-core/src/main/java/org/ethereum/rpc/dto/TransactionResultDTO.java +++ b/rskj-core/src/main/java/org/ethereum/rpc/dto/TransactionResultDTO.java @@ -18,19 +18,20 @@ package org.ethereum.rpc.dto; -import org.ethereum.core.Block; -import org.ethereum.core.Transaction; -import org.ethereum.crypto.signature.ECDSASignature; - import co.rsk.core.Coin; import co.rsk.remasc.RemascTransaction; import co.rsk.util.HexUtils; +import org.ethereum.core.Block; +import org.ethereum.core.Transaction; +import org.ethereum.crypto.signature.ECDSASignature; /** * Created by Ruben on 8/1/2016. */ public class TransactionResultDTO { + private static final String HEX_ZERO = "0x0"; + private String hash; private String nonce; private String blockHash; @@ -46,7 +47,7 @@ public class TransactionResultDTO { private String r; private String s; - public TransactionResultDTO(Block b, Integer index, Transaction tx) { + public TransactionResultDTO(Block b, Integer index, Transaction tx, boolean zeroSignatureIfRemasc) { hash = tx.getHash().toJsonString(); nonce = HexUtils.toQuantityJsonHex(tx.getNonce()); @@ -69,13 +70,18 @@ public TransactionResultDTO(Block b, Integer index, Transaction tx) { input = HexUtils.toUnformattedJsonHex(tx.getData()); - if (!(tx instanceof RemascTransaction)) { + boolean isRemasc = tx instanceof RemascTransaction; + if (!isRemasc) { ECDSASignature signature = tx.getSignature(); v = String.format("0x%02x", tx.getEncodedV()); r = HexUtils.toQuantityJsonHex(signature.getR()); s = HexUtils.toQuantityJsonHex(signature.getS()); + } else if (zeroSignatureIfRemasc) { + v = HEX_ZERO; + r = HEX_ZERO; + s = HEX_ZERO; } } @@ -135,4 +141,4 @@ public String getS() { return s; } -} \ No newline at end of file +} diff --git a/rskj-core/src/main/resources/expected.conf b/rskj-core/src/main/resources/expected.conf index 84e47b2f3d3..d9a680710d3 100644 --- a/rskj-core/src/main/resources/expected.conf +++ b/rskj-core/src/main/resources/expected.conf @@ -260,6 +260,7 @@ rpc = { } ] skipRemasc: + zeroSignatureIfRemasc = gasEstimationCap = } wire = { diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index 2d87eefd243..db8c24544f2 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -159,8 +159,8 @@ miner { # the number of milliseconds that should pass from a previous submission of a mining solution before next one is allowed # set this value to zero or any negative number to disable this limit workSubmissionRateLimitInMills = 0 - - # Toggles the behaviour of the miner server to prepare a new work for the miners when the node gets a new pending transaction + + # Toggles the behaviour of the miner server to prepare a new work for the miners when the node gets a new pending transaction updateWorkOnNewTransaction = false } @@ -413,6 +413,8 @@ rpc { } ] skipRemasc: false + # set signature to zero (instead of null) for Remasc transaction on RPC DTOs + zeroSignatureIfRemasc = true gasEstimationCap = 6800000 # block gasLimit, rpc DoS protection for gas estimation } diff --git a/rskj-core/src/test/java/org/ethereum/rpc/dto/BlockResultDTOTest.java b/rskj-core/src/test/java/org/ethereum/rpc/dto/BlockResultDTOTest.java index bf263ba4bec..c0a39e480be 100644 --- a/rskj-core/src/test/java/org/ethereum/rpc/dto/BlockResultDTOTest.java +++ b/rskj-core/src/test/java/org/ethereum/rpc/dto/BlockResultDTOTest.java @@ -18,17 +18,12 @@ package org.ethereum.rpc.dto; -import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.math.BigInteger; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - +import co.rsk.core.BlockDifficulty; +import co.rsk.core.genesis.TestGenesisLoader; +import co.rsk.remasc.RemascTransaction; +import co.rsk.test.builders.BlockBuilder; +import co.rsk.test.builders.TransactionBuilder; +import co.rsk.util.HexUtils; import org.ethereum.core.Block; import org.ethereum.core.Blockchain; import org.ethereum.core.Transaction; @@ -39,14 +34,21 @@ import org.junit.Before; import org.junit.Test; -import co.rsk.core.BlockDifficulty; -import co.rsk.core.genesis.TestGenesisLoader; -import co.rsk.remasc.RemascTransaction; -import co.rsk.test.builders.BlockBuilder; -import co.rsk.test.builders.TransactionBuilder; -import co.rsk.util.HexUtils; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class BlockResultDTOTest { + + private static final String HEX_ZERO = "0x0"; + private Block block; private BlockStore blockStore; public static final Transaction TRANSACTION = new TransactionBuilder().buildRandomTransaction(); @@ -63,7 +65,7 @@ public void setup() { @Test public void getBlockResultDTOWithRemascAndTransactionHashes() { - BlockResultDTO blockResultDTO = BlockResultDTO.fromBlock(block, false, blockStore, false); + BlockResultDTO blockResultDTO = BlockResultDTO.fromBlock(block, false, blockStore, false, false); List transactionHashes = transactionHashesByBlock(blockResultDTO); Assert.assertNotNull(blockResultDTO); @@ -74,7 +76,7 @@ public void getBlockResultDTOWithRemascAndTransactionHashes() { @Test public void getBlockResultDTOWithoutRemascAndTransactionHashes() { - BlockResultDTO blockResultDTO = BlockResultDTO.fromBlock(block, false, blockStore, true); + BlockResultDTO blockResultDTO = BlockResultDTO.fromBlock(block, false, blockStore, true, false); List transactionHashes = transactionHashesByBlock(blockResultDTO); Assert.assertNotNull(blockResultDTO); @@ -86,7 +88,7 @@ public void getBlockResultDTOWithoutRemascAndTransactionHashes() { @Test public void getBlockResultDTOWithoutRemasc_emptyTransactions() { Block block = buildBlockWithTransactions(Arrays.asList(REMASC_TRANSACTION)); - BlockResultDTO blockResultDTO = BlockResultDTO.fromBlock(block, false, blockStore, true); + BlockResultDTO blockResultDTO = BlockResultDTO.fromBlock(block, false, blockStore, true, false); Assert.assertEquals(HexUtils.toUnformattedJsonHex(EMPTY_TRIE_HASH), blockResultDTO.getTransactionsRoot()); @@ -96,20 +98,41 @@ public void getBlockResultDTOWithoutRemasc_emptyTransactions() { @Test - public void getBlockResultDTOWithRemascAndFullTransactions() { - BlockResultDTO blockResultDTO = BlockResultDTO.fromBlock(block, true, blockStore, false); + public void getBlockResultDTOWithNullSignatureRemascAndFullTransactions() { + BlockResultDTO blockResultDTO = BlockResultDTO.fromBlock(block, true, blockStore, false, false); + Assert.assertNotNull(blockResultDTO); + Assert.assertEquals(2, blockResultDTO.getTransactions().size()); - List transactionResultsHashes = transactionResultsByBlock(blockResultDTO).stream().map(e -> e.getHash()).collect(Collectors.toList()); + TransactionResultDTO regularTransaction = (TransactionResultDTO) blockResultDTO.getTransactions().get(0); + Assert.assertNotNull(regularTransaction); + + TransactionResultDTO remascTransaction = (TransactionResultDTO) blockResultDTO.getTransactions().get(1); + Assert.assertNotNull(remascTransaction); + Assert.assertNull(remascTransaction.getV()); + Assert.assertNull(remascTransaction.getR()); + Assert.assertNull(remascTransaction.getS()); + } + + @Test + public void getBlockResultDTOWithWithZeroSignatureRemascAndFullTransactions() { + BlockResultDTO blockResultDTO = BlockResultDTO.fromBlock(block, true, blockStore, false, true); Assert.assertNotNull(blockResultDTO); Assert.assertEquals(2, blockResultDTO.getTransactions().size()); - Assert.assertTrue(transactionResultsHashes.contains(TRANSACTION.getHash().toJsonString())); - Assert.assertTrue(transactionResultsHashes.contains(REMASC_TRANSACTION.getHash().toJsonString())); + + TransactionResultDTO regularTransaction = (TransactionResultDTO) blockResultDTO.getTransactions().get(0); + Assert.assertNotNull(regularTransaction); + + TransactionResultDTO remascTransaction = (TransactionResultDTO) blockResultDTO.getTransactions().get(1); + Assert.assertNotNull(remascTransaction); + Assert.assertEquals(HEX_ZERO, remascTransaction.getV()); + Assert.assertEquals(HEX_ZERO, remascTransaction.getR()); + Assert.assertEquals(HEX_ZERO, remascTransaction.getS()); } @Test public void getBlockResultDTOWithoutRemascAndFullTransactions() { - BlockResultDTO blockResultDTO = BlockResultDTO.fromBlock(block, true, blockStore, true); + BlockResultDTO blockResultDTO = BlockResultDTO.fromBlock(block, true, blockStore, true, false); List transactionResultsHashes = transactionResultsByBlock(blockResultDTO).stream().map(e -> e.getHash()).collect(Collectors.toList()); diff --git a/rskj-core/src/test/java/org/ethereum/rpc/dto/TransactionResultDTOTest.java b/rskj-core/src/test/java/org/ethereum/rpc/dto/TransactionResultDTOTest.java index 9eb78e3dd39..56ebce73ced 100644 --- a/rskj-core/src/test/java/org/ethereum/rpc/dto/TransactionResultDTOTest.java +++ b/rskj-core/src/test/java/org/ethereum/rpc/dto/TransactionResultDTOTest.java @@ -31,10 +31,13 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.*; import static org.mockito.Mockito.mock; public class TransactionResultDTOTest { + + private static final String HEX_ZERO = "0x0"; + private final TestSystemProperties config = new TestSystemProperties(); private final byte chainId = config.getNetworkConstants().getChainId(); @@ -42,7 +45,7 @@ public class TransactionResultDTOTest { public void remascAddressSerialization() { RemascTransaction remascTransaction = new RemascTransaction(new Random().nextLong()); - TransactionResultDTO dto = new TransactionResultDTO(mock(Block.class), 42, remascTransaction); + TransactionResultDTO dto = new TransactionResultDTO(mock(Block.class), 42, remascTransaction, false); assertThat(dto.getFrom(), is("0x0000000000000000000000000000000000000000")); assertThat(dto.getR(), is(nullValue())); assertThat(dto.getS(), is(nullValue())); @@ -58,7 +61,7 @@ public void signedTransactionWithChainIdSerialization() { originalTransaction.sign(new byte[]{}); - TransactionResultDTO dto = new TransactionResultDTO(mock(Block.class), 42, originalTransaction); + TransactionResultDTO dto = new TransactionResultDTO(mock(Block.class), 42, originalTransaction, false); Assert.assertNotNull(dto.getR()); Assert.assertNotNull(dto.getS()); @@ -78,7 +81,7 @@ public void transactionWithZeroNonce() { originalTransaction.sign(new byte[]{}); - TransactionResultDTO dto = new TransactionResultDTO(mock(Block.class), 42, originalTransaction); + TransactionResultDTO dto = new TransactionResultDTO(mock(Block.class), 42, originalTransaction, false); Assert.assertNotNull(dto.getNonce()); Assert.assertEquals("0x0", dto.getNonce()); @@ -93,10 +96,28 @@ public void transactionWithOneNonceWithoutLeadingZeroes() { originalTransaction.sign(new byte[]{}); - TransactionResultDTO dto = new TransactionResultDTO(mock(Block.class), 42, originalTransaction); + TransactionResultDTO dto = new TransactionResultDTO(mock(Block.class), 42, originalTransaction, false); Assert.assertNotNull(dto.getNonce()); Assert.assertEquals("0x1", dto.getNonce()); } + + @Test + public void transactionRemascHasSignatureNullWhenFlagIsFalse() { + RemascTransaction remascTransaction = new RemascTransaction(new Random().nextLong()); + TransactionResultDTO dto = new TransactionResultDTO(mock(Block.class), 42, remascTransaction, false); + assertNull(dto.getV()); + assertNull(dto.getR()); + assertNull(dto.getS()); + } + + @Test + public void transactionRemascHasSignatureZeroWhenFlagIsTrue() { + RemascTransaction remascTransaction = new RemascTransaction(new Random().nextLong()); + TransactionResultDTO dto = new TransactionResultDTO(mock(Block.class), 42, remascTransaction, true); + assertEquals(HEX_ZERO, dto.getV()); + assertEquals(HEX_ZERO, dto.getR()); + assertEquals(HEX_ZERO, dto.getS()); + } }