Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding new rsk_getStorageBytesAt JSON-RPC method #2191

Merged
merged 3 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions rskj-core/src/main/java/co/rsk/rpc/Web3RskModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
package co.rsk.rpc;

import co.rsk.rpc.modules.rsk.RskModule;
import org.ethereum.rpc.parameters.BlockRefParam;
import org.ethereum.rpc.parameters.HexAddressParam;
import org.ethereum.rpc.parameters.HexNumberParam;

public interface Web3RskModule {

Expand Down Expand Up @@ -47,4 +50,7 @@ default void rsk_flush() {
}

RskModule getRskModule();

String rsk_getStorageBytesAt(HexAddressParam address, HexNumberParam storageIdx, BlockRefParam blockRefParam);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to understand, is there a reason why the default keyword isn't declared?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm only declaring the method and in this case, it is not needed to add default implementation.

default methods are used when you want to implement a default method behavior within an interface to not break compatibility with older implementations. It is mainly used in high-exposure interfaces but here it is not needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great, huge thanks angel.


}
52 changes: 36 additions & 16 deletions rskj-core/src/main/java/org/ethereum/rpc/Web3Impl.java
Original file line number Diff line number Diff line change
Expand Up @@ -465,41 +465,61 @@ public String eth_getBalance(HexAddressParam address) {
public String eth_getStorageAt(HexAddressParam address, HexNumberParam storageIdx, BlockRefParam blockRefParam) {
if (blockRefParam.getIdentifier() != null) {
return this.eth_getStorageAt(address, storageIdx, blockRefParam.getIdentifier());
} else {
return this.eth_getStorageAt(address, storageIdx, blockRefParam.getInputs());
}
return this.eth_getStorageAt(address, storageIdx, blockRefParam.getInputs());
}

private String eth_getStorageAt(HexAddressParam address, HexNumberParam storageIdx, Map<String, String> blockRef) {
return invokeByBlockRef(blockRef, blockNumber -> this.eth_getStorageAt(address, storageIdx, blockNumber));
}

private String eth_getStorageAt(HexAddressParam address, HexNumberParam storageIdx, String blockId) {
String s = null;
String response = null;

try {
RskAddress addr = address.getAddress();

AccountInformationProvider accountInformationProvider =
web3InformationRetriever.getInformationProvider(blockId);
DataWord key = DataWord.valueOf(HexUtils.strHexOrStrNumberToByteArray(storageIdx.getHexNumber()));

DataWord sv = accountInformationProvider
.getStorageValue(addr, DataWord.valueOf(HexUtils.strHexOrStrNumberToByteArray(storageIdx.getHexNumber())));
response = Optional.ofNullable(accountInformationProvider.getStorageValue(address.getAddress(), key))
.map(DataWord::getData)
.map(HexUtils::toUnformattedJsonHex)
.orElse("0x0");
return response;
} finally {
logger.debug("eth_getStorageAt({}, {}, {}): {}", address, storageIdx, blockId, response);
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
}
}

if (sv == null) {
s = "0x0";
} else {
s = HexUtils.toUnformattedJsonHex(sv.getData());
}
@Override
public String rsk_getStorageBytesAt(HexAddressParam address, HexNumberParam storageIdx, BlockRefParam blockRefParam) {
if (blockRefParam.getIdentifier() != null) {
return this.rsk_getStorageBytesAt(address, storageIdx, blockRefParam.getIdentifier());
}
return this.rsk_getStorageBytesAt(address, storageIdx, blockRefParam.getInputs());
}

return s;
private String rsk_getStorageBytesAt(HexAddressParam address, HexNumberParam storageIdx, String blockId) {
String response = null;

try {
AccountInformationProvider accountInformationProvider =
web3InformationRetriever.getInformationProvider(blockId);
DataWord key = DataWord.valueOf(HexUtils.strHexOrStrNumberToByteArray(storageIdx.getHexNumber()));

response = Optional.ofNullable(accountInformationProvider.getStorageBytes(address.getAddress(), key))
.map(HexUtils::toUnformattedJsonHex)
.orElse("0x0");
return response;
} finally {
if (logger.isDebugEnabled()) {
logger.debug("eth_getStorageAt({}, {}, {}): {}", address, storageIdx, blockId, s);
}
logger.debug("rsk_getStorageAt({}, {}, {}): {}", address, storageIdx, blockId, response);
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
}
}

private String rsk_getStorageBytesAt(HexAddressParam address, HexNumberParam storageIdx, Map<String, String> blockRef) {
return invokeByBlockRef(blockRef, blockNumber -> this.rsk_getStorageBytesAt(address, storageIdx, blockNumber));
}

@Override
public String eth_getTransactionCount(HexAddressParam address, BlockRefParam blockRefParam) {
if (blockRefParam.getIdentifier() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ public RskAddress getAddress() {
return address;
}

@Override
public String toString() {
return address.toString();
}

public static class Deserializer extends StdDeserializer<HexAddressParam> {
private static final long serialVersionUID = 1L;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ public String getHexNumber() {
return this.hexNumber;
}

@Override
public String toString() {
return this.hexNumber;
}

public static class Deserializer extends StdDeserializer<HexNumberParam> {
private static final long serialVersionUID = 1L;

Expand Down
2 changes: 1 addition & 1 deletion rskj-core/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ rpc {
version: "1.0",
enabled: "true",
methods: {
disabled: [ "rsk_shutdown", "rsk_flush" ]
disabled: [ "rsk_shutdown", "rsk_flush", "rsk_getStorageBytesAt" ]
}
}
}
Expand Down
106 changes: 70 additions & 36 deletions rskj-core/src/test/java/org/ethereum/rpc/Web3ImplUnitTest.java
Original file line number Diff line number Diff line change
@@ -1,41 +1,5 @@
package org.ethereum.rpc;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.ethereum.TestUtils;
import org.ethereum.core.*;
import org.ethereum.db.BlockStore;
import org.ethereum.db.ReceiptStore;
import org.ethereum.facade.Ethereum;
import org.ethereum.net.client.ConfigCapabilities;
import org.ethereum.net.server.ChannelManager;
import org.ethereum.net.server.PeerServer;
import org.ethereum.rpc.exception.RskJsonRpcRequestException;
import org.ethereum.rpc.parameters.BlockHashParam;
import org.ethereum.rpc.parameters.BlockIdentifierParam;
import org.ethereum.rpc.parameters.BlockRefParam;
import org.ethereum.rpc.parameters.HexAddressParam;
import org.ethereum.rpc.parameters.HexNumberParam;
import org.ethereum.util.BuildInfo;
import org.ethereum.util.TransactionFactoryHelper;
import org.ethereum.vm.DataWord;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import co.rsk.config.RskSystemProperties;
import co.rsk.core.Coin;
import co.rsk.core.RskAddress;
Expand All @@ -55,6 +19,29 @@
import co.rsk.rpc.modules.txpool.TxPoolModule;
import co.rsk.scoring.PeerScoringManager;
import co.rsk.util.HexUtils;
import org.ethereum.TestUtils;
import org.ethereum.core.*;
import org.ethereum.db.BlockStore;
import org.ethereum.db.ReceiptStore;
import org.ethereum.facade.Ethereum;
import org.ethereum.net.client.ConfigCapabilities;
import org.ethereum.net.server.ChannelManager;
import org.ethereum.net.server.PeerServer;
import org.ethereum.rpc.exception.RskJsonRpcRequestException;
import org.ethereum.rpc.parameters.*;
import org.ethereum.util.BuildInfo;
import org.ethereum.util.TransactionFactoryHelper;
import org.ethereum.vm.DataWord;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.math.BigInteger;
import java.util.*;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;

class Web3ImplUnitTest {

Expand Down Expand Up @@ -226,6 +213,53 @@ void eth_getStorageAtEmptyCell() {
result);
}

@Test
void rsk_getStorageBytesAt() {
String id = "0x00";
String addr = "0x0011223344556677880011223344556677889900";
RskAddress expectedAddress = new RskAddress(addr);
String storageIdx = "0x01";
DataWord expectedIdx = DataWord.valueOf(HexUtils.stringHexToByteArray(storageIdx));

HexAddressParam hexAddressParam = new HexAddressParam(addr);
HexNumberParam hexNumberParam = new HexNumberParam(storageIdx);
BlockRefParam blockRefParam = new BlockRefParam(id);
byte[] resultBytes = TestUtils.generateBytes("result",64);

AccountInformationProvider aip = mock(AccountInformationProvider.class);
when(retriever.getInformationProvider(id)).thenReturn(aip);
when(aip.getStorageBytes(expectedAddress, expectedIdx))
.thenReturn(resultBytes);

String expectedResult = HexUtils.toUnformattedJsonHex(resultBytes);

String result = target.rsk_getStorageBytesAt(hexAddressParam, hexNumberParam, blockRefParam);
assertEquals(expectedResult,
result);
}

@Test
void rsk_getStorageBytesAtEmptyCell() {
String id = "0x00";
String addr = "0x0011223344556677880011223344556677889900";
RskAddress expectedAddress = new RskAddress(addr);
String storageIdx = "0x01";
DataWord expectedIdx = DataWord.valueOf(HexUtils.stringHexToByteArray(storageIdx));

HexAddressParam hexAddressParam = new HexAddressParam(addr);
HexNumberParam hexNumberParam = new HexNumberParam(storageIdx);
BlockRefParam blockRefParam = new BlockRefParam(id);

AccountInformationProvider aip = mock(AccountInformationProvider.class);
when(retriever.getInformationProvider(id)).thenReturn(aip);
when(aip.getStorageValue(expectedAddress, expectedIdx))
.thenReturn(null);

String result = target.rsk_getStorageBytesAt(hexAddressParam, hexNumberParam, blockRefParam);
assertEquals("0x0",
result);
}

@Test
void eth_getBlockTransactionCountByNumber_blockNotFound() {
String id = "0x00";
Expand Down
Loading