Skip to content

Commit 3ff3e52

Browse files
nagarevfmacleal
authored andcommitted
Refactoring validations
1 parent b2fff19 commit 3ff3e52

16 files changed

+386
-104
lines changed

rskj-core/src/main/java/co/rsk/RskContext.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
import org.ethereum.sync.SyncPool;
131131
import org.ethereum.util.BuildInfo;
132132
import org.ethereum.util.FileUtil;
133+
import org.ethereum.vm.OverrideablePrecompiledContracts;
133134
import org.ethereum.vm.PrecompiledContracts;
134135
import org.ethereum.vm.program.invoke.ProgramInvokeFactory;
135136
import org.ethereum.vm.program.invoke.ProgramInvokeFactoryImpl;
@@ -252,6 +253,7 @@ public class RskContext implements NodeContext, NodeBootstrapper {
252253
private BlockExecutor blockExecutor;
253254
private BtcBlockStoreWithCache.Factory btcBlockStoreFactory;
254255
private PrecompiledContracts precompiledContracts;
256+
private OverrideablePrecompiledContracts overrideablePrecompiledContracts;
255257
private BridgeSupportFactory bridgeSupportFactory;
256258
private PeersInformation peersInformation;
257259
private StatusResolver statusResolver;
@@ -498,6 +500,16 @@ public synchronized BlockExecutor getBlockExecutor() {
498500
return blockExecutor;
499501
}
500502

503+
public synchronized OverrideablePrecompiledContracts getOverrideablePrecompiledContracts() {
504+
checkIfNotClosed();
505+
506+
if (overrideablePrecompiledContracts == null) {
507+
overrideablePrecompiledContracts = new OverrideablePrecompiledContracts(getPrecompiledContracts());
508+
}
509+
510+
return overrideablePrecompiledContracts;
511+
}
512+
501513
public synchronized PrecompiledContracts getPrecompiledContracts() {
502514
checkIfNotClosed();
503515

@@ -735,7 +747,8 @@ public synchronized EthModule getEthModule() {
735747
getBridgeSupportFactory(),
736748
getRskSystemProperties().getGasEstimationCap(),
737749
getRskSystemProperties().getCallGasCap(),
738-
getPrecompiledContracts(),
750+
getRskSystemProperties().getActivationConfig(),
751+
getOverrideablePrecompiledContracts(),
739752
getRskSystemProperties().getAllowCallStateOverride(),
740753
getStateOverrideApplier()
741754
);
@@ -860,7 +873,7 @@ public synchronized TraceModule getTraceModule() {
860873
getBlockExecutor(),
861874
getExecutionBlockRetriever(),
862875
getBlockTxSignatureCache(),
863-
rskSystemProperties
876+
getRskSystemProperties()
864877
);
865878
}
866879

rskj-core/src/main/java/co/rsk/rpc/modules/eth/DefaultStateOverrideApplier.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ public DefaultStateOverrideApplier(ActivationConfig activationConfig) {
3737
this.activationConfig = activationConfig;
3838
}
3939

40+
@Override
41+
public boolean containsStateChange(AccountOverride accountOverride) {
42+
boolean containsStateChange = accountOverride.getBalance() != null || accountOverride.getNonce() != null || accountOverride.getCode() != null;
43+
boolean containsStateDiff = accountOverride.getState() != null || accountOverride.getStateDiff() != null;
44+
return containsStateChange || containsStateDiff;
45+
}
46+
4047
@Override
4148
public void applyToRepository(Block block, Repository repository, AccountOverride accountOverride, OverrideablePrecompiledContracts overrideablePrecompiledContracts) {
4249

@@ -73,7 +80,11 @@ public void applyToRepository(Block block, Repository repository, AccountOverrid
7380
}
7481
}
7582

76-
if (overrideablePrecompiledContracts != null && accountOverride.getMovePrecompileToAddress() != null && accountOverride.getAddress() != null) {
83+
if (overrideablePrecompiledContracts != null && accountOverride.getMovePrecompileToAddress() != null) {
84+
if (!overrideablePrecompiledContracts.isMovableContract(accountOverride.getAddress())) {
85+
throw new IllegalStateException(String.format("Account %s can not be moved", accountOverride.getAddress().toHexString()));
86+
}
87+
7788
if (overrideablePrecompiledContracts.isOverridden(accountOverride.getAddress())) {
7889
throw new IllegalStateException(String.format("Account %s has already been overridden by a precompile", accountOverride.getAddress().toHexString()));
7990
}

rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModule.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import co.rsk.util.HexUtils;
3434
import com.google.common.annotations.VisibleForTesting;
3535
import org.apache.commons.lang3.tuple.Pair;
36+
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
3637
import org.ethereum.core.Block;
3738
import org.ethereum.core.Blockchain;
3839
import org.ethereum.core.CallTransaction;
@@ -49,6 +50,7 @@
4950
import org.ethereum.rpc.parameters.CallArgumentsParam;
5051
import org.ethereum.rpc.parameters.HexAddressParam;
5152
import org.ethereum.rpc.parameters.HexDataParam;
53+
import org.ethereum.vm.DataWord;
5254
import org.ethereum.vm.GasCost;
5355
import org.ethereum.vm.PrecompiledContracts;
5456
import org.ethereum.vm.OverrideablePrecompiledContracts;
@@ -87,7 +89,8 @@ public class EthModule
8789
private final byte chainId;
8890
private final long gasEstimationCap;
8991
private final long gasCallCap;
90-
private final PrecompiledContracts precompiledContracts;
92+
private final ActivationConfig activationConfig;
93+
private final OverrideablePrecompiledContracts overrideablePrecompiledContracts;
9194
private final boolean allowCallStateOverride;
9295
private final StateOverrideApplier stateOverrideApplier;
9396

@@ -104,7 +107,8 @@ public EthModule(
104107
BridgeSupportFactory bridgeSupportFactory,
105108
long gasEstimationCap,
106109
long gasCallCap,
107-
PrecompiledContracts precompiledContracts,
110+
ActivationConfig activationConfig,
111+
OverrideablePrecompiledContracts overrideablePrecompiledContracts,
108112
boolean allowCallStateOverride,
109113
StateOverrideApplier stateOverrideApplier) {
110114
this.chainId = chainId;
@@ -119,7 +123,8 @@ public EthModule(
119123
this.bridgeSupportFactory = bridgeSupportFactory;
120124
this.gasEstimationCap = gasEstimationCap;
121125
this.gasCallCap = gasCallCap;
122-
this.precompiledContracts = precompiledContracts;
126+
this.activationConfig = activationConfig;
127+
this.overrideablePrecompiledContracts = overrideablePrecompiledContracts;
123128
this.allowCallStateOverride = allowCallStateOverride;
124129
this.stateOverrideApplier = stateOverrideApplier;
125130
}
@@ -155,7 +160,6 @@ public String call(CallArgumentsParam argsParam, BlockIdentifierParam bnOrId, Li
155160
ExecutionBlockRetriever.Result result = executionBlockRetriever.retrieveExecutionBlock(bnOrId.getIdentifier());
156161
Block block = result.getBlock();
157162

158-
OverrideablePrecompiledContracts overrideablePrecompiledContracts = new OverrideablePrecompiledContracts(precompiledContracts);
159163
MutableRepository mutableRepository = prepareRepository(result, block, shouldPerformStateOverride, accountOverrideList, overrideablePrecompiledContracts);
160164

161165
CallArguments callArgs = argsParam.toCallArguments();
@@ -202,7 +206,13 @@ private MutableRepository prepareRepository(ExecutionBlockRetriever.Result resul
202206
}
203207

204208
private void applyStateOverride(Block block, MutableRepository mutableRepository, List<AccountOverride> accountOverrideList, OverrideablePrecompiledContracts overrideablePrecompiledContracts) {
209+
ActivationConfig.ForBlock blockActivations = activationConfig.forBlock(block.getNumber());
205210
for (AccountOverride accountOverride : accountOverrideList) {
211+
PrecompiledContracts.PrecompiledContract precompiledContract = overrideablePrecompiledContracts
212+
.getContractForAddress(blockActivations, DataWord.valueFromHex(accountOverride.getAddress().toHexString()));
213+
if (precompiledContract != null && stateOverrideApplier.containsStateChange(accountOverride)) {
214+
throw invalidParamError("Precompiled contracts can not be overridden");
215+
}
206216
stateOverrideApplier.applyToRepository(block, mutableRepository, accountOverride, overrideablePrecompiledContracts);
207217
}
208218
}

rskj-core/src/main/java/co/rsk/rpc/modules/eth/StateOverrideApplier.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@
2222
import org.ethereum.vm.OverrideablePrecompiledContracts;
2323

2424
public interface StateOverrideApplier {
25+
boolean containsStateChange(AccountOverride accountOverride);
2526
void applyToRepository(Block block, Repository repository, AccountOverride accountOverride, OverrideablePrecompiledContracts overrideablePrecompiledContracts);
2627
}

rskj-core/src/main/java/org/ethereum/vm/OverrideablePrecompiledContracts.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@
2121
import co.rsk.core.RskAddress;
2222
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
2323

24-
import java.util.ArrayList;
24+
import java.util.Arrays;
2525
import java.util.HashMap;
26-
import java.util.List;
26+
import java.util.HashSet;
2727
import java.util.Map;
28+
import java.util.Set;
2829

2930
public class OverrideablePrecompiledContracts extends PrecompiledContracts {
3031
private final Map<RskAddress, PrecompiledContract> overriddenPrecompileContracts = new HashMap<>();
31-
private final List<RskAddress> overriddenContracts = new ArrayList<>();
32+
private final Set<RskAddress> overriddenContracts = new HashSet<>();
3233

3334
public OverrideablePrecompiledContracts(PrecompiledContracts basePrecompiledContracts) {
3435
super(basePrecompiledContracts.getConfig(), basePrecompiledContracts.getBridgeSupportFactory(), basePrecompiledContracts.getSignatureCache());
@@ -59,4 +60,10 @@ public void addOverride(RskAddress originalAddress, RskAddress targetAddress, Ac
5960
public boolean isOverridden(RskAddress address) {
6061
return overriddenContracts.stream().anyMatch(a -> a.equals(address));
6162
}
63+
64+
public boolean isMovableContract(RskAddress contractAddress) {
65+
byte[] addressBytes = contractAddress.getBytes();
66+
return !Arrays.equals(BRIDGE_ADDR.getBytes(), addressBytes) && !Arrays.equals(REMASC_ADDR.getBytes(), addressBytes);
67+
}
68+
6269
}

rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
import org.ethereum.util.ByteUtil;
7979
import org.ethereum.util.TransactionFactoryHelper;
8080
import org.ethereum.vm.GasCost;
81+
import org.ethereum.vm.OverrideablePrecompiledContracts;
8182
import org.ethereum.vm.PrecompiledContracts;
8283
import org.ethereum.vm.program.invoke.ProgramInvokeFactoryImpl;
8384
import org.junit.jupiter.api.Assertions;
@@ -644,6 +645,11 @@ private Web3Impl internalCreateEnvironment(Blockchain blockchain,
644645

645646
final RepositoryBtcBlockStoreWithCache.Factory btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory(
646647
config.getNetworkConstants().getBridgeConstants().getBtcParams());
648+
649+
BridgeSupportFactory bridgeSupportFactory = new BridgeSupportFactory(
650+
btcBlockStoreFactory, config.getNetworkConstants().getBridgeConstants(),
651+
config.getActivationConfig(), signatureCache);
652+
647653
EthModule ethModule = new EthModule(
648654
config.getNetworkConstants().getBridgeConstants(), config.getNetworkConstants().getChainId(), blockchain, transactionPool,
649655
reversibleTransactionExecutor1, new ExecutionBlockRetriever(blockchain, null, null),
@@ -653,7 +659,10 @@ repositoryLocator, new EthModuleWalletEnabled(wallet, transactionPool, signature
653659
config.getActivationConfig(), signatureCache),
654660
config.getGasEstimationCap(),
655661
config.getCallGasCap(),
656-
null,
662+
config.getActivationConfig(),
663+
new OverrideablePrecompiledContracts(
664+
new PrecompiledContracts(config, bridgeSupportFactory, signatureCache)
665+
),
657666
false,
658667
new DefaultStateOverrideApplier(config.getActivationConfig())
659668
);

rskj-core/src/test/java/co/rsk/rpc/modules/eth/DefaultStateOverrideApplierTest.java

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,33 @@
2828
import co.rsk.trie.TrieStore;
2929
import co.rsk.trie.TrieStoreImpl;
3030
import org.ethereum.TestUtils;
31-
import org.ethereum.core.*;
31+
import org.ethereum.config.blockchain.upgrades.ActivationConfig;
32+
import org.ethereum.core.Block;
33+
import org.ethereum.core.BlockTxSignatureCache;
34+
import org.ethereum.core.ReceivedTxSignatureCache;
35+
import org.ethereum.core.Repository;
36+
import org.ethereum.core.SignatureCache;
3237
import org.ethereum.datasource.HashMapDB;
3338
import org.ethereum.db.MutableRepository;
39+
import org.ethereum.rpc.parameters.AccountOverrideParam;
40+
import org.ethereum.rpc.parameters.HexAddressParam;
41+
import org.ethereum.rpc.parameters.HexDataParam;
42+
import org.ethereum.rpc.parameters.HexNumberParam;
3443
import org.ethereum.vm.DataWord;
3544
import org.ethereum.vm.OverrideablePrecompiledContracts;
3645
import org.ethereum.vm.PrecompiledContracts;
3746
import org.junit.jupiter.api.BeforeEach;
3847
import org.junit.jupiter.api.Test;
48+
import org.junit.jupiter.params.ParameterizedTest;
49+
import org.junit.jupiter.params.provider.Arguments;
50+
import org.junit.jupiter.params.provider.MethodSource;
51+
3952
import java.math.BigInteger;
4053
import java.util.HashMap;
4154
import java.util.Map;
55+
import java.util.stream.Stream;
4256

57+
import static org.ethereum.vm.PrecompiledContracts.BRIDGE_ADDR_STR;
4358
import static org.junit.jupiter.api.Assertions.*;
4459
import static org.mockito.Mockito.mock;
4560
import static org.mockito.Mockito.when;
@@ -202,7 +217,39 @@ void applyWithMovePrecompileTo_happyPath() {
202217
stateOverrideApplier.applyToRepository(blockMock, repository, accountOverride, overrideablePrecompiledContracts);
203218

204219
// Then
205-
assertEquals(overrideablePrecompiledContracts.getContractForAddress(testSystemProperties.getActivationConfig().forBlock(blockNumber), precompileAddressInDataWord), overrideablePrecompiledContracts.getContractForAddress(testSystemProperties.getActivationConfig().forBlock(blockNumber), movePrecompileToInDataWord));
220+
ActivationConfig.ForBlock blockActivations = testSystemProperties.getActivationConfig().forBlock(blockNumber);
221+
222+
PrecompiledContracts.PrecompiledContract originalContract = overrideablePrecompiledContracts.getContractForAddress(blockActivations, precompileAddressInDataWord);
223+
PrecompiledContracts.PrecompiledContract movedContract = overrideablePrecompiledContracts.getContractForAddress(blockActivations, movePrecompileToInDataWord);
224+
225+
assertEquals(originalContract, movedContract);
226+
}
227+
228+
@Test
229+
void applyWithMovePrecompileTo_notMovableContract_throwsExceptionAsExpected() {
230+
// Given
231+
RskAddress bridgeAddress = new RskAddress(BRIDGE_ADDR_STR);
232+
RskAddress movePrecompileTo = TestUtils.generateAddress("targetAddress");
233+
234+
AccountOverride accountOverride = new AccountOverride(bridgeAddress);
235+
accountOverride.setMovePrecompileToAddress(movePrecompileTo);
236+
237+
PrecompiledContracts precompiledContracts = getPrecompiledContracts();
238+
239+
OverrideablePrecompiledContracts overrideablePrecompiledContracts = new OverrideablePrecompiledContracts(precompiledContracts);
240+
241+
long blockNumber = 1L;
242+
Block blockMock = mock(Block.class);
243+
when(blockMock.getNumber()).thenReturn(blockNumber);
244+
245+
// When
246+
IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
247+
// This is the second time calling the exact same method so the contract should be already overridden
248+
stateOverrideApplier.applyToRepository(blockMock, repository, accountOverride, overrideablePrecompiledContracts);
249+
});
250+
251+
// Then
252+
assertEquals("Account " + bridgeAddress.toHexString() + " can not be moved", exception.getMessage());
206253
}
207254

208255
@Test
@@ -234,6 +281,12 @@ void applyWithMovePrecompileTo_alreadyOverriddenContract_throwsExceptionAsExpect
234281
assertEquals("Account " + precompileAddress.toHexString() + " has already been overridden by a precompile", exception.getMessage());
235282
}
236283

284+
@ParameterizedTest
285+
@MethodSource("provideContainsStateChangeTestCases")
286+
void containsStateChange_executesAsExpected(AccountOverride accountOverride, boolean expectedResult) {
287+
assertEquals(expectedResult, stateOverrideApplier.containsStateChange(accountOverride));
288+
}
289+
237290
private PrecompiledContracts getPrecompiledContracts() {
238291
TestSystemProperties config = new TestSystemProperties();
239292
SignatureCache signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache());
@@ -242,4 +295,25 @@ private PrecompiledContracts getPrecompiledContracts() {
242295
return new PrecompiledContracts(config, bridgeSupportFactory, signatureCache);
243296
}
244297

298+
private static Stream<Arguments> provideContainsStateChangeTestCases() {
299+
return Stream.of(
300+
Arguments.of(getAccountOverride(new AccountOverrideParam(null, null, null, null, null, null)), false),
301+
Arguments.of(getAccountOverride(new AccountOverrideParam(null, null, null, null, null, new HexAddressParam("0x0000000000000000000000000000000000000001"))), false),
302+
Arguments.of(getAccountOverride(new AccountOverrideParam(new HexNumberParam("0x01"), null, null, null, null, new HexAddressParam("0x0000000000000000000000000000000000000001"))), true),
303+
Arguments.of(getAccountOverride(new AccountOverrideParam(new HexNumberParam("0x01"), null, null, null, null, null)), true),
304+
Arguments.of(getAccountOverride(new AccountOverrideParam(null, new HexNumberParam("0x01"), null, null, null, null)), true),
305+
Arguments.of(getAccountOverride(new AccountOverrideParam(null, null, new HexDataParam("0x01"), null, null, null)), true),
306+
Arguments.of(getAccountOverride(new AccountOverrideParam(null, null, null, new HashMap<>(), null, null)), true),
307+
Arguments.of(getAccountOverride(new AccountOverrideParam(null, null, null, null, new HashMap<>(), null)), true),
308+
Arguments.of(getAccountOverride(new AccountOverrideParam(new HexNumberParam("0x01"), new HexNumberParam("0x01"), new HexDataParam("0x01"), new HashMap<>(), new HashMap<>(), new HexAddressParam("0x0000000000000000000000000000000000000001"))), true),
309+
Arguments.of(getAccountOverride(new AccountOverrideParam(new HexNumberParam("0x01"), new HexNumberParam("0x01"), new HexDataParam("0x01"), new HashMap<>(), new HashMap<>(), null)), true)
310+
);
311+
}
312+
313+
private static AccountOverride getAccountOverride(AccountOverrideParam accountOverrideParam) {
314+
RskAddress address = TestUtils.generateAddress("test");
315+
AccountOverride accountOverride = new AccountOverride(address);
316+
return accountOverride.fromAccountOverrideParam(accountOverrideParam);
317+
}
318+
245319
}

rskj-core/src/test/java/co/rsk/rpc/modules/eth/EthModuleGasEstimationDSLTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
* You should have received a copy of the GNU Lesser General Public License
1717
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
*/
19-
2019
package co.rsk.rpc.modules.eth;
2120

2221
import co.rsk.config.TestSystemProperties;

0 commit comments

Comments
 (0)