Adds priv_getcode (#428)

* Adds priv_getcode

Signed-off-by: Joshua Richardson <joshua@richardson.tech>
This commit is contained in:
Lucas Saldanha
2020-02-25 11:16:58 +13:00
committed by GitHub
parent 7fe1d4796e
commit bfc40be32e
11 changed files with 287 additions and 7 deletions

View File

@@ -1,6 +1,7 @@
# Changelog
## 1.4.1
- Added priv_getCode [\#250](https://github.com/hyperledger/besu/pull/408). Gets the bytecode associated with a private address.
### Bug Fixes

View File

@@ -0,0 +1,29 @@
/*
* 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.privacy.condition;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
import org.web3j.tx.Contract;
public class ExpectValidContractCode implements PrivateContractCondition {
@Override
public void verify(final Contract contract) throws IOException {
assertThat(contract).isNotNull();
assertThat(contract.isValid()).isEqualTo(true);
}
}

View File

@@ -14,8 +14,10 @@
*/
package org.hyperledger.besu.tests.acceptance.dsl.privacy.condition;
import java.io.IOException;
import org.web3j.tx.Contract;
public interface PrivateContractCondition {
void verify(final Contract contract);
void verify(final Contract contract) throws IOException;
}

View File

@@ -22,4 +22,8 @@ public class PrivateContractVerifier {
final String contractAddress, final String senderAddress) {
return new ExpectValidPrivateContractDeployedReceipt(contractAddress, senderAddress);
}
public ExpectValidContractCode validContractCodeProvided() {
return new ExpectValidContractCode();
}
}

View File

@@ -32,10 +32,12 @@ public class CustomRequestFactory {
public TransactionReceiptWithRevertReason() {}
@Override
public void setRevertReason(final String revertReason) {
this.revertReason = revertReason;
}
@Override
public String getRevertReason() {
return revertReason;
}

View File

@@ -36,7 +36,7 @@ public class DeployPrivateSmartContractAcceptanceTest extends PrivacyAcceptanceT
}
@Test
public void deployingMustGiveValidReceipt() {
public void deployingMustGiveValidReceiptAndCode() throws Exception {
final String contractAddress = "0x89ce396d0f9f937ddfa71113e29b2081c4869555";
final EventEmitter eventEmitter =
@@ -50,5 +50,7 @@ public class DeployPrivateSmartContractAcceptanceTest extends PrivacyAcceptanceT
privateContractVerifier
.validPrivateContractDeployed(contractAddress, minerNode.getAddress().toString())
.verify(eventEmitter);
privateContractVerifier.validContractCodeProvided().verify(eventEmitter);
}
}

View File

@@ -46,6 +46,7 @@ public enum RpcMethod {
PRIV_FIND_PRIVACY_GROUP("priv_findPrivacyGroup"),
PRIV_DISTRIBUTE_RAW_TRANSACTION("priv_distributeRawTransaction"),
PRIV_GET_EEA_TRANSACTION_COUNT("priv_getEeaTransactionCount"),
PRIV_GET_CODE("priv_getCode"),
EEA_SEND_RAW_TRANSACTION("eea_sendRawTransaction"),
ETH_ACCOUNTS("eth_accounts"),
ETH_BLOCK_NUMBER("eth_blockNumber"),

View File

@@ -0,0 +1,85 @@
/*
* 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.ethereum.api.jsonrpc.internal.privacy.methods.priv;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.AbstractBlockParameterMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.privacy.PrivateStateRootResolver;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
public class PrivGetCode extends AbstractBlockParameterMethod {
private final BlockchainQueries blockchain;
private final PrivateStateRootResolver privateStateRootResolver;
private final WorldStateArchive privateWorldStateArchive;
public PrivGetCode(
final BlockchainQueries blockchainQueries,
final WorldStateArchive privateWorldStateArchive,
final PrivateStateRootResolver privateStateRootResolver) {
super(blockchainQueries);
this.privateWorldStateArchive = privateWorldStateArchive;
this.blockchain = blockchainQueries;
this.privateStateRootResolver = privateStateRootResolver;
}
@Override
public String getName() {
return RpcMethod.PRIV_GET_CODE.getMethodName();
}
@Override
protected BlockParameter blockParameter(final JsonRpcRequestContext request) {
return request.getRequiredParameter(2, BlockParameter.class);
}
@Override
protected Object resultByBlockNumber(
final JsonRpcRequestContext request, final long blockNumber) {
final String privacyGroupId = request.getRequiredParameter(0, String.class);
final Address address = Address.fromHexString(request.getRequiredParameter(1, String.class));
final Hash latestStateRoot =
privateStateRootResolver.resolveLastStateRoot(
Bytes32.wrap(Bytes.fromBase64String(privacyGroupId)),
blockchain.getBlockchain().getBlockByNumber(blockNumber).orElseThrow().getHash());
return privateWorldStateArchive
.get(latestStateRoot)
.flatMap(
pws ->
Optional.ofNullable(pws.get(address)).map(account -> account.getCode().toString()))
.map(c -> new JsonRpcSuccessResponse(request.getRequest().getId(), c))
.orElse(new JsonRpcSuccessResponse(request.getRequest().getId(), null));
}
@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
return (JsonRpcResponse) findResultByParamType(requestContext);
}
}

View File

@@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.P
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivDeletePrivacyGroup;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivDistributeRawTransaction;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivFindPrivacyGroup;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetCode;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetPrivacyPrecompileAddress;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetPrivateTransaction;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv.PrivGetTransactionCount;
@@ -32,6 +33,7 @@ import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateStateRootResolver;
import java.util.Map;
@@ -68,6 +70,10 @@ public class PrivJsonRpcMethods extends PrivacyApiGroupJsonRpcMethods {
new PrivGetPrivateTransaction(
getBlockchainQueries(), privacyController, enclavePublicKeyProvider),
new PrivDistributeRawTransaction(privacyController, enclavePublicKeyProvider),
new PrivCall(getBlockchainQueries(), privacyController, enclavePublicKeyProvider));
new PrivCall(getBlockchainQueries(), privacyController, enclavePublicKeyProvider),
new PrivGetCode(
getBlockchainQueries(),
getPrivacyParameters().getPrivateWorldStateArchive(),
new PrivateStateRootResolver(getPrivacyParameters().getPrivateStateStorage())));
}
}

View File

@@ -0,0 +1,148 @@
/*
* 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.ethereum.api.jsonrpc.internal.privacy.methods.priv;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.core.WorldState;
import org.hyperledger.besu.ethereum.privacy.PrivateStateRootResolver;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.privacy.Restriction;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import java.math.BigInteger;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class PrivGetCodeTest {
private final Address sender =
Address.fromHexString("0x0000000000000000000000000000000000000003");
private static final SECP256K1.KeyPair KEY_PAIR =
SECP256K1.KeyPair.create(
SECP256K1.PrivateKey.create(
new BigInteger(
"8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", 16)));
private final Bytes privacyGroupId =
Bytes.fromBase64String("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=");
private final PrivateTransaction.Builder privateTransactionBuilder =
PrivateTransaction.builder()
.nonce(0)
.gasPrice(Wei.of(1000))
.gasLimit(3000000)
.to(null)
.value(Wei.ZERO)
.payload(
Bytes.fromBase64String(
"0x608060405234801561001057600080fd5b5060d08061001f60003960"
+ "00f3fe60806040526004361060485763ffffffff7c01000000"
+ "00000000000000000000000000000000000000000000000000"
+ "60003504166360fe47b18114604d5780636d4ce63c14607557"
+ "5b600080fd5b348015605857600080fd5b5060736004803603"
+ "6020811015606d57600080fd5b50356099565b005b34801560"
+ "8057600080fd5b506087609e565b6040805191825251908190"
+ "0360200190f35b600055565b6000549056fea165627a7a7230"
+ "5820cb1d0935d14b589300b12fcd0ab849a7e9019c81da24d6"
+ "daa4f6b2f003d1b0180029"))
.sender(sender)
.chainId(BigInteger.valueOf(2018))
.privateFrom(Bytes.fromBase64String("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="))
.restriction(Restriction.RESTRICTED);
private PrivGetCode method;
@Mock private BlockchainQueries mockBlockchainQueries;
@Mock private Blockchain mockBlockchain;
@Mock private Block mockBlock;
@Mock private Hash mockHash;
@Mock private PrivateStateRootResolver mockResolver;
@Mock private WorldStateArchive mockPrivateWorldStateArchive;
@Mock private WorldState mockWorldState;
@Mock private Account mockAccount;
private final Hash lastStateRoot =
Hash.fromHexString("0x2121b68f1333e93bae8cd717a3ca68c9d7e7003f6b288c36dfc59b0f87be9590");
private final Bytes contractAccountCode = Bytes.fromBase64String("ZXhhbXBsZQ==");
@Before
public void before() {
method = new PrivGetCode(mockBlockchainQueries, mockPrivateWorldStateArchive, mockResolver);
}
@Test
public void returnValidCodeWhenCalledOnValidContract() {
final PrivateTransaction transaction =
privateTransactionBuilder.privacyGroupId(privacyGroupId).signAndBuild(KEY_PAIR);
final Address contractAddress =
Address.privateContractAddress(
transaction.getSender(), transaction.getNonce(), privacyGroupId);
mockBlockchainWithContractCode(contractAddress);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest(
"2.0",
"priv_getCode",
new Object[] {
"Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=",
contractAddress.toHexString(),
"latest"
}));
final JsonRpcResponse response = method.response(request);
assertThat(response).isInstanceOf(JsonRpcSuccessResponse.class);
assertThat(((JsonRpcSuccessResponse) response).getResult())
.isEqualTo(contractAccountCode.toString());
}
private void mockBlockchainWithContractCode(final Address resultantContractAddress) {
when(mockBlockchainQueries.getBlockchain()).thenReturn(mockBlockchain);
when(mockBlockchain.getBlockByNumber(anyLong())).thenReturn(Optional.of(mockBlock));
when(mockBlock.getHash()).thenReturn(mockHash);
when(mockResolver.resolveLastStateRoot(any(Bytes32.class), any(Hash.class)))
.thenReturn(lastStateRoot);
when(mockPrivateWorldStateArchive.get(lastStateRoot)).thenReturn(Optional.of(mockWorldState));
when(mockWorldState.get(resultantContractAddress)).thenReturn(mockAccount);
when(mockAccount.getCode()).thenReturn(contractAccountCode);
}
}

View File

@@ -95,10 +95,10 @@ dependencyManagement {
dependency 'org.springframework.security:spring-security-crypto:5.2.1.RELEASE'
dependency 'org.web3j:abi:4.5.11'
dependency 'org.web3j:besu:4.5.11'
dependency 'org.web3j:core:4.5.11'
dependency 'org.web3j:crypto:4.5.11'
dependency 'org.web3j:abi:4.5.15'
dependency 'org.web3j:besu:4.5.15'
dependency 'org.web3j:core:4.5.15'
dependency 'org.web3j:crypto:4.5.15'
dependency 'org.xerial.snappy:snappy-java:1.1.7.3'