mirror of https://github.com/hyperledger/besu
[Issue 1975] Add option to require tx replay protection (#2497)
* Add option to enforce tx replay protection for local txs * Only enforce replay protection if the current milestone supports it * moved changelog entry to next release Signed-off-by: Meredith Baxter <meredith.baxter@palm.io> Signed-off-by: Sally MacFarlane <sally.macfarlane@consensys.net> Co-authored-by: Sally MacFarlane <sally.macfarlane@consensys.net>sonarTour
parent
19ca28f9a2
commit
e860de96ed
@ -0,0 +1,43 @@ |
||||
/* |
||||
* Copyright ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.tests.acceptance.dsl.condition.eth; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.WaitUtils; |
||||
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition; |
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.Node; |
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.eth.EthSendRawTransactionTransaction; |
||||
|
||||
import org.apache.tuweni.bytes.Bytes32; |
||||
|
||||
public class ExpectSuccessfulEthSendRawTransaction implements Condition { |
||||
|
||||
private final EthSendRawTransactionTransaction transaction; |
||||
|
||||
public ExpectSuccessfulEthSendRawTransaction(final EthSendRawTransactionTransaction transaction) { |
||||
this.transaction = transaction; |
||||
} |
||||
|
||||
@Override |
||||
public void verify(final Node node) { |
||||
WaitUtils.waitFor( |
||||
5, |
||||
() -> { |
||||
final Bytes32 txHash = Bytes32.fromHexString(node.execute(transaction)); |
||||
assertThat(txHash).isNotNull(); |
||||
}); |
||||
} |
||||
} |
@ -1,23 +0,0 @@ |
||||
/* |
||||
* Copyright ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
* |
||||
*/ |
||||
package org.hyperledger.besu.tests.acceptance.dsl.transaction; |
||||
|
||||
import org.hyperledger.besu.crypto.SignatureAlgorithm; |
||||
|
||||
@FunctionalInterface |
||||
public interface TransactionWithSignatureAlgorithm<T> { |
||||
T execute(final NodeRequests node, final SignatureAlgorithm signatureAlgorithm); |
||||
} |
@ -0,0 +1,120 @@ |
||||
/* |
||||
* Copyright ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
* |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
package org.hyperledger.besu.tests.acceptance.jsonrpc; |
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; |
||||
import org.hyperledger.besu.tests.acceptance.dsl.account.Account; |
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.Node; |
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.BesuNodeConfigurationBuilder; |
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationFactory; |
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.account.TransferTransaction; |
||||
|
||||
import java.math.BigInteger; |
||||
import java.util.function.UnaryOperator; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
public class EthSendRawTransactionTest extends AcceptanceTestBase { |
||||
private static final long CHAIN_ID = 20211; |
||||
|
||||
private Account sender; |
||||
|
||||
private Node lenientNode; |
||||
private Node strictNode; |
||||
private Node miningNode; |
||||
|
||||
@Before |
||||
public void setUp() throws Exception { |
||||
sender = accounts.getPrimaryBenefactor(); |
||||
|
||||
lenientNode = besu.createArchiveNode("lenientNode", configureNode((false))); |
||||
strictNode = besu.createArchiveNode("strictNode", configureNode((true))); |
||||
miningNode = besu.createMinerNode("strictMiningNode", configureNode((true))); |
||||
cluster.start(lenientNode, strictNode, miningNode); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldSendSuccessfullyToLenientNodeWithoutChainId() { |
||||
final TransferTransaction tx = createTransactionWithoutChainId(); |
||||
final String rawTx = tx.signedTransactionData(); |
||||
final String txHash = tx.transactionHash(); |
||||
|
||||
lenientNode.verify(eth.expectSuccessfulEthRawTransaction(rawTx)); |
||||
// Tx should be included on-chain
|
||||
miningNode.verify(eth.expectSuccessfulTransactionReceipt(txHash)); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldFailToSendToToStrictNodeWithoutChainId() { |
||||
final TransferTransaction tx = createTransactionWithoutChainId(); |
||||
final String rawTx = tx.signedTransactionData(); |
||||
|
||||
strictNode.verify(eth.expectEthSendRawTransactionException(rawTx, "ChainId is required")); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldSendSuccessfullyWithChainId_lenientNode() { |
||||
final TransferTransaction tx = createTransactionWithChainId(); |
||||
final String rawTx = tx.signedTransactionData(); |
||||
final String txHash = tx.transactionHash(); |
||||
|
||||
lenientNode.verify(eth.expectSuccessfulEthRawTransaction(rawTx)); |
||||
// Tx should be included on-chain
|
||||
miningNode.verify(eth.expectSuccessfulTransactionReceipt(txHash)); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldSendSuccessfullyWithChainId_strictNode() { |
||||
final TransferTransaction tx = createTransactionWithChainId(); |
||||
final String rawTx = tx.signedTransactionData(); |
||||
final String txHash = tx.transactionHash(); |
||||
|
||||
strictNode.verify(eth.expectSuccessfulEthRawTransaction(rawTx)); |
||||
// Tx should be included on-chain
|
||||
miningNode.verify(eth.expectSuccessfulTransactionReceipt(txHash)); |
||||
} |
||||
|
||||
private TransferTransaction createTransactionWithChainId() { |
||||
return createTransaction(true); |
||||
} |
||||
|
||||
private TransferTransaction createTransactionWithoutChainId() { |
||||
return createTransaction(false); |
||||
} |
||||
|
||||
private TransferTransaction createTransaction(final boolean withChainId) { |
||||
if (withChainId) { |
||||
return accountTransactions.createTransfer(createAccount(), 2, CHAIN_ID); |
||||
} else { |
||||
final BigInteger nonce = |
||||
miningNode.execute(ethTransactions.getTransactionCount(sender.getAddress())); |
||||
return accountTransactions.createTransfer( |
||||
accounts.getPrimaryBenefactor(), createAccount(), 1, nonce); |
||||
} |
||||
} |
||||
|
||||
private UnaryOperator<BesuNodeConfigurationBuilder> configureNode( |
||||
final boolean enableStrictReplayProtection) { |
||||
return b -> |
||||
b.genesisConfigProvider(GenesisConfigurationFactory::createDevLondonGenesisConfig) |
||||
.strictTxReplayProtectionEnabled(enableStrictReplayProtection) |
||||
.devMode(false); |
||||
} |
||||
|
||||
private Account createAccount() { |
||||
return accounts.createAccount("Test account"); |
||||
} |
||||
} |
@ -0,0 +1,43 @@ |
||||
{ |
||||
"config":{ |
||||
"chainId":20211, |
||||
"homesteadBlock":0, |
||||
"eip150Block":0, |
||||
"eip155Block":0, |
||||
"eip158Block":0, |
||||
"byzantiumBlock":0, |
||||
"constantinopleBlock":0, |
||||
"petersburgBlock":0, |
||||
"istanbulBlock":0, |
||||
"berlinBlock":0, |
||||
"londonBlock":0, |
||||
"ethash":{ |
||||
"fixeddifficulty": 1 |
||||
} |
||||
}, |
||||
"alloc":{ |
||||
"fe3b557e8fb62b89f4916b721be55ceb828dbd73": { |
||||
"privateKey": "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", |
||||
"comment": "private key and this comment are ignored. In a real chain, the private key should NOT be stored", |
||||
"balance": "0xad78ebc5ac6200000" |
||||
}, |
||||
"627306090abaB3A6e1400e9345bC60c78a8BEf57": { |
||||
"privateKey": "c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3", |
||||
"comment": "private key and this comment are ignored. In a real chain, the private key should NOT be stored", |
||||
"balance": "90000000000000000000000" |
||||
}, |
||||
"f17f52151EbEF6C7334FAD080c5704D77216b732": { |
||||
"privateKey": "ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f", |
||||
"comment": "private key and this comment are ignored. In a real chain, the private key should NOT be stored", |
||||
"balance": "90000000000000000000000" |
||||
} |
||||
}, |
||||
"coinbase":"0x0000000000000000000000000000000000000000", |
||||
"difficulty":"0x00001", |
||||
"extraData":"0x5365706f6c69612c20417468656e732c204174746963612c2047726565636521", |
||||
"gasLimit":"0x1c9c380", |
||||
"nonce":"0x000000000000000", |
||||
"mixhash":"0x0000000000000000000000000000000000000000000000000000000000000000", |
||||
"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", |
||||
"timestamp":"0x6159af19" |
||||
} |
Loading…
Reference in new issue