mirror of https://github.com/hyperledger/besu
[PRIV] Complete Private Transaction Processor (#938)
* Remove entries() in KeyValueStorage * Implement Private Transaction Processor * Implement PrivateTransactionReceipt * Refactor privacy parameter injection * Disable ether for private transaction * Implement AcceptanceTest * Fix PrivateWorldState injection * Add unimplemented private transaction type - https://entethalliance.github.io/client-spec/spec.html#sec-extensions-json-rpc * Change Private Transaction RLP * Change Private Transaction RLP for acceptanceTest * Fix copyright year * Fix build Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>pull/2/head
parent
6176a63049
commit
582454581a
@ -0,0 +1,48 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.PrivateTransactionReceiptResponse; |
||||
|
||||
import java.util.Collections; |
||||
|
||||
import org.assertj.core.util.Lists; |
||||
import org.web3j.protocol.Web3jService; |
||||
import org.web3j.protocol.core.Request; |
||||
|
||||
public class EeaJsonRpcRequestFactory { |
||||
|
||||
private final Web3jService web3jService; |
||||
|
||||
public EeaJsonRpcRequestFactory(final Web3jService web3jService) { |
||||
this.web3jService = web3jService; |
||||
} |
||||
|
||||
public Request<?, org.web3j.protocol.core.methods.response.EthSendTransaction> |
||||
eeaSendRawTransaction(final String signedTransactionData) { |
||||
return new Request<>( |
||||
"eea_sendRawTransaction", |
||||
Collections.singletonList(signedTransactionData), |
||||
web3jService, |
||||
org.web3j.protocol.core.methods.response.EthSendTransaction.class); |
||||
} |
||||
|
||||
public Request<?, PrivateTransactionReceiptResponse> eeaGetTransactionReceipt( |
||||
final String txHash, final String publicKey) { |
||||
return new Request<>( |
||||
"eea_getTransactionReceipt", |
||||
Lists.newArrayList(txHash, publicKey), |
||||
web3jService, |
||||
PrivateTransactionReceiptResponse.class); |
||||
} |
||||
} |
@ -0,0 +1,46 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eea; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.JsonRequestFactories; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.PrivateTransactionReceipt; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.PrivateTransactionReceiptResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
public class EeaGetTransactionReceiptTransaction implements Transaction<PrivateTransactionReceipt> { |
||||
|
||||
private final String txHash; |
||||
private final String publicKey; |
||||
|
||||
public EeaGetTransactionReceiptTransaction(final String txHash, final String publicKey) { |
||||
this.txHash = txHash; |
||||
this.publicKey = publicKey; |
||||
} |
||||
|
||||
@Override |
||||
public PrivateTransactionReceipt execute(final JsonRequestFactories node) { |
||||
try { |
||||
final PrivateTransactionReceiptResponse result = |
||||
node.eea().eeaGetTransactionReceipt(txHash, publicKey).send(); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.hasError()).isFalse(); |
||||
return result.getResult(); |
||||
} catch (IOException e) { |
||||
return null; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,42 @@ |
||||
/* |
||||
* Copyright 2018 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eea; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.JsonRequestFactories; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import org.web3j.protocol.core.methods.response.EthSendTransaction; |
||||
|
||||
public class EeaSendRawTransactionTransaction implements Transaction<String> { |
||||
|
||||
private final String transactionData; |
||||
|
||||
public EeaSendRawTransactionTransaction(final String transactionData) { |
||||
this.transactionData = transactionData; |
||||
} |
||||
|
||||
@Override |
||||
public String execute(final JsonRequestFactories node) { |
||||
try { |
||||
EthSendTransaction response = node.eea().eeaSendRawTransaction(transactionData).send(); |
||||
assertThat(response.getTransactionHash()).isNotNull(); |
||||
return response.getTransactionHash(); |
||||
} catch (final IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,183 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.web3j.privacy; |
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8; |
||||
import static org.junit.Assert.assertEquals; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; |
||||
|
||||
import tech.pegasys.orion.testutil.OrionTestHarness; |
||||
import tech.pegasys.pantheon.crypto.SECP256K1; |
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; |
||||
import tech.pegasys.pantheon.ethereum.core.Wei; |
||||
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction; |
||||
import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.AcceptanceTestBase; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.PrivateTransactionReceipt; |
||||
import tech.pegasys.pantheon.util.bytes.BytesValue; |
||||
|
||||
import java.math.BigInteger; |
||||
|
||||
import com.google.common.collect.Lists; |
||||
import org.junit.After; |
||||
import org.junit.Before; |
||||
import org.junit.ClassRule; |
||||
import org.junit.Test; |
||||
import org.junit.rules.TemporaryFolder; |
||||
import org.web3j.crypto.Credentials; |
||||
import org.web3j.protocol.core.methods.response.TransactionReceipt; |
||||
|
||||
public class DeployPrivateSmartContractAcceptanceTest extends AcceptanceTestBase { |
||||
|
||||
@ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); |
||||
|
||||
// Contract address is generated from sender address and transaction nonce
|
||||
private static final Address CONTRACT_ADDRESS = |
||||
Address.fromHexString("0x42699a7612a82f1d9c36148af9c77354759b210b"); |
||||
|
||||
private static final Address SENDER = |
||||
Address.fromHexString( |
||||
Credentials.create("8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63") |
||||
.getAddress()); |
||||
|
||||
private static final PrivateTransaction DEPLOY_CONTRACT = |
||||
PrivateTransaction.builder() |
||||
.nonce(0) |
||||
.gasPrice(Wei.of(1000)) |
||||
.gasLimit(3000000) |
||||
.to(null) |
||||
.value(Wei.ZERO) |
||||
.payload( |
||||
BytesValue.fromHexString( |
||||
"0x608060405234801561001057600080fd5b5060d08061001f60003960" |
||||
+ "00f3fe60806040526004361060485763ffffffff7c01000000" |
||||
+ "00000000000000000000000000000000000000000000000000" |
||||
+ "60003504166360fe47b18114604d5780636d4ce63c14607557" |
||||
+ "5b600080fd5b348015605857600080fd5b5060736004803603" |
||||
+ "6020811015606d57600080fd5b50356099565b005b34801560" |
||||
+ "8057600080fd5b506087609e565b6040805191825251908190" |
||||
+ "0360200190f35b600055565b6000549056fea165627a7a7230" |
||||
+ "5820cb1d0935d14b589300b12fcd0ab849a7e9019c81da24d6" |
||||
+ "daa4f6b2f003d1b0180029")) |
||||
.sender(SENDER) |
||||
.chainId(2018) |
||||
.privateFrom( |
||||
BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8))) |
||||
.privateFor( |
||||
Lists.newArrayList( |
||||
BytesValue.wrap("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=".getBytes(UTF_8)))) |
||||
.restriction(BytesValue.wrap("unrestricted".getBytes(UTF_8))) |
||||
.signAndBuild( |
||||
SECP256K1.KeyPair.create( |
||||
SECP256K1.PrivateKey.create( |
||||
new BigInteger( |
||||
"8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", |
||||
16)))); |
||||
|
||||
private static final PrivateTransaction FUNCTION_CALL = |
||||
PrivateTransaction.builder() |
||||
.nonce(1) |
||||
.gasPrice(Wei.of(1000)) |
||||
.gasLimit(3000000) |
||||
.to(CONTRACT_ADDRESS) |
||||
.value(Wei.ZERO) |
||||
.payload( |
||||
BytesValue.fromHexString( |
||||
"0xcccdda2cf2895862749f1c69aa9f55cf481ea82500e4eabb4e2578b36636979b" |
||||
+ "0000000000000000000000000000000000000000000000000000000000000000")) |
||||
.sender(SENDER) |
||||
.chainId(2018) |
||||
.privateFrom( |
||||
BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8))) |
||||
.privateFor( |
||||
Lists.newArrayList( |
||||
BytesValue.wrap("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=".getBytes(UTF_8)))) |
||||
.restriction(BytesValue.wrap("unrestricted".getBytes(UTF_8))) |
||||
.signAndBuild( |
||||
SECP256K1.KeyPair.create( |
||||
SECP256K1.PrivateKey.create( |
||||
new BigInteger( |
||||
"8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", |
||||
16)))); |
||||
|
||||
private PantheonNode minerNode; |
||||
|
||||
private OrionTestHarness testHarness; |
||||
|
||||
@Before |
||||
public void setUp() throws Exception { |
||||
testHarness = OrionTestHarness.create(folder.newFolder().toPath()); |
||||
|
||||
final PrivacyParameters privacyParameters = new PrivacyParameters(); |
||||
privacyParameters.setUrl(testHarness.clientUrl()); |
||||
privacyParameters.setPrivacyAddress(Address.PRIVACY); |
||||
privacyParameters.setPublicKeyUsingFile(testHarness.getConfig().publicKeys().get(0).toFile()); |
||||
privacyParameters.enablePrivateDB(folder.newFolder("private").toPath()); |
||||
|
||||
minerNode = pantheon.createPrivateTransactionEnabledMinerNode("miner-node", privacyParameters); |
||||
cluster.start(minerNode); |
||||
} |
||||
|
||||
@After |
||||
public void tearDownOnce() { |
||||
testHarness.getOrion().stop(); |
||||
} |
||||
|
||||
@Test |
||||
public void deployingMustGiveValidReceipt() { |
||||
|
||||
final String signedRawDeployTransaction = toRlp(DEPLOY_CONTRACT); |
||||
|
||||
final String transactionHash = |
||||
minerNode.execute(transactions.createPrivateRawTransaction(signedRawDeployTransaction)); |
||||
|
||||
minerNode.waitUntil(wait.chainHeadHasProgressed(minerNode, 2)); |
||||
|
||||
waitFor(() -> minerNode.verify(eth.expectSuccessfulTransactionReceipt(transactionHash))); |
||||
|
||||
TransactionReceipt txReceipt = |
||||
minerNode.execute(transactions.getTransactionReceipt(transactionHash)).get(); |
||||
|
||||
assertEquals(Address.DEFAULT_PRIVACY.toString(), txReceipt.getTo()); |
||||
|
||||
PrivateTransactionReceipt privateTxReceipt = |
||||
minerNode.execute( |
||||
transactions.getPrivateTransactionReceipt( |
||||
transactionHash, "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=")); |
||||
|
||||
assertEquals(CONTRACT_ADDRESS.toString(), privateTxReceipt.getContractAddress()); |
||||
|
||||
final String signedRawFunctionTransaction = toRlp(FUNCTION_CALL); |
||||
|
||||
final String transactionHash1 = |
||||
minerNode.execute(transactions.createPrivateRawTransaction(signedRawFunctionTransaction)); |
||||
|
||||
minerNode.waitUntil(wait.chainHeadHasProgressed(minerNode, 2)); |
||||
|
||||
waitFor(() -> minerNode.verify(eth.expectSuccessfulTransactionReceipt(transactionHash1))); |
||||
|
||||
TransactionReceipt txReceipt2 = |
||||
minerNode.execute(transactions.getTransactionReceipt(transactionHash)).get(); |
||||
|
||||
// TODO: fire function call from minerNode and from a non-privy node
|
||||
|
||||
} |
||||
|
||||
private String toRlp(final PrivateTransaction transaction) { |
||||
BytesValueRLPOutput bvrlpo = new BytesValueRLPOutput(); |
||||
transaction.writeTo(bvrlpo); |
||||
return bvrlpo.encoded().toString(); |
||||
} |
||||
} |
@ -0,0 +1,93 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.privacy; |
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8; |
||||
|
||||
import tech.pegasys.pantheon.enclave.Enclave; |
||||
import tech.pegasys.pantheon.enclave.types.ReceiveRequest; |
||||
import tech.pegasys.pantheon.enclave.types.ReceiveResponse; |
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
import tech.pegasys.pantheon.ethereum.core.Transaction; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.JsonRpcMethod; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.privacy.PrivateTransactionReceiptResult; |
||||
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction; |
||||
import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPInput; |
||||
import tech.pegasys.pantheon.util.bytes.BytesValue; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Base64; |
||||
import java.util.Optional; |
||||
|
||||
public class EeaGetTransactionReceipt implements JsonRpcMethod { |
||||
|
||||
private final BlockchainQueries blockchain; |
||||
private final Enclave enclave; |
||||
private final JsonRpcParameter parameters; |
||||
|
||||
public EeaGetTransactionReceipt( |
||||
final BlockchainQueries blockchain, |
||||
final Enclave enclave, |
||||
final JsonRpcParameter parameters) { |
||||
this.blockchain = blockchain; |
||||
this.enclave = enclave; |
||||
this.parameters = parameters; |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return "eea_getTransactionReceipt"; |
||||
} |
||||
|
||||
@Override |
||||
public JsonRpcResponse response(final JsonRpcRequest request) { |
||||
final Hash hash = parameters.required(request.getParams(), 0, Hash.class); |
||||
final String publicKey = parameters.required(request.getParams(), 1, String.class); |
||||
final Optional<Transaction> transactionCompleteResult = |
||||
blockchain.getBlockchain().getTransactionByHash(hash); |
||||
final PrivateTransactionReceiptResult result = |
||||
transactionCompleteResult |
||||
.map( |
||||
t -> { |
||||
final ReceiveRequest enclaveRequest = |
||||
new ReceiveRequest( |
||||
new String(t.getPayload().extractArray(), UTF_8), publicKey); |
||||
try { |
||||
ReceiveResponse enclaveResponse = enclave.receive(enclaveRequest); |
||||
final BytesValueRLPInput bytesValueRLPInput = |
||||
new BytesValueRLPInput( |
||||
BytesValue.wrap( |
||||
Base64.getDecoder().decode(enclaveResponse.getPayload())), |
||||
false); |
||||
PrivateTransaction pt = PrivateTransaction.readFrom(bytesValueRLPInput); |
||||
final String contractAddress = |
||||
Address.contractAddress(pt.getSender(), pt.getNonce()).toString(); |
||||
// TODO(PRIV): Return internal transaction emitted events and return values
|
||||
return new PrivateTransactionReceiptResult( |
||||
contractAddress, |
||||
pt.getSender().toString(), |
||||
pt.getTo().map(Address::toString).orElse(null)); |
||||
} catch (IOException e) { |
||||
return null; |
||||
} |
||||
}) |
||||
.orElse(null); |
||||
return new JsonRpcSuccessResponse(request.getId(), result); |
||||
} |
||||
} |
@ -0,0 +1,77 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.privacy; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
import tech.pegasys.pantheon.ethereum.core.Log; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.TransactionReceiptLogResult; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter; |
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder; |
||||
|
||||
@JsonPropertyOrder({ |
||||
"contractAddress", |
||||
"from", |
||||
"to", |
||||
}) |
||||
public class PrivateTransactionReceiptResult { |
||||
|
||||
private final String contractAddress; |
||||
private final String from; |
||||
private final String to; |
||||
|
||||
public PrivateTransactionReceiptResult( |
||||
final String contractAddress, final String from, final String to) { |
||||
|
||||
this.contractAddress = contractAddress; |
||||
this.from = from; |
||||
// TODO: handle logs as in TransactionReceiptResult
|
||||
this.to = to; |
||||
} |
||||
|
||||
@JsonGetter(value = "contractAddress") |
||||
public String getContractAddress() { |
||||
return contractAddress; |
||||
} |
||||
|
||||
@JsonGetter(value = "from") |
||||
public String getFrom() { |
||||
return from; |
||||
} |
||||
|
||||
@JsonGetter(value = "to") |
||||
public String getTo() { |
||||
return to; |
||||
} |
||||
|
||||
private List<TransactionReceiptLogResult> logReceipts( |
||||
final List<Log> logs, |
||||
final long blockNumber, |
||||
final Hash transactionHash, |
||||
final Hash blockHash, |
||||
final int transactionIndex) { |
||||
final List<TransactionReceiptLogResult> logResults = new ArrayList<>(logs.size()); |
||||
|
||||
for (int i = 0; i < logs.size(); i++) { |
||||
final Log log = logs.get(i); |
||||
logResults.add( |
||||
new TransactionReceiptLogResult( |
||||
log, blockNumber, transactionHash, blockHash, transactionIndex, i)); |
||||
} |
||||
|
||||
return logResults; |
||||
} |
||||
} |
@ -0,0 +1,132 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.privacy; |
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8; |
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.mockito.ArgumentMatchers.any; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
import tech.pegasys.pantheon.crypto.SECP256K1; |
||||
import tech.pegasys.pantheon.enclave.Enclave; |
||||
import tech.pegasys.pantheon.enclave.types.ReceiveRequest; |
||||
import tech.pegasys.pantheon.enclave.types.ReceiveResponse; |
||||
import tech.pegasys.pantheon.ethereum.chain.Blockchain; |
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
import tech.pegasys.pantheon.ethereum.core.Transaction; |
||||
import tech.pegasys.pantheon.ethereum.core.Wei; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.privacy.PrivateTransactionReceiptResult; |
||||
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction; |
||||
import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPOutput; |
||||
import tech.pegasys.pantheon.util.bytes.BytesValue; |
||||
|
||||
import java.io.IOException; |
||||
import java.math.BigInteger; |
||||
import java.util.Base64; |
||||
import java.util.Optional; |
||||
|
||||
import com.google.common.collect.Lists; |
||||
import org.junit.Test; |
||||
|
||||
public class EeaGetTransactionReceiptTest { |
||||
|
||||
private final Address sender = |
||||
Address.fromHexString("0x0000000000000000000000000000000000000003"); |
||||
private final PrivateTransaction privateTransaction = |
||||
PrivateTransaction.builder() |
||||
.nonce(0) |
||||
.gasPrice(Wei.of(1000)) |
||||
.gasLimit(3000000) |
||||
.to(null) |
||||
.value(Wei.ZERO) |
||||
.payload( |
||||
BytesValue.fromHexString( |
||||
"0x608060405234801561001057600080fd5b5060d08061001f60003960" |
||||
+ "00f3fe60806040526004361060485763ffffffff7c01000000" |
||||
+ "00000000000000000000000000000000000000000000000000" |
||||
+ "60003504166360fe47b18114604d5780636d4ce63c14607557" |
||||
+ "5b600080fd5b348015605857600080fd5b5060736004803603" |
||||
+ "6020811015606d57600080fd5b50356099565b005b34801560" |
||||
+ "8057600080fd5b506087609e565b6040805191825251908190" |
||||
+ "0360200190f35b600055565b6000549056fea165627a7a7230" |
||||
+ "5820cb1d0935d14b589300b12fcd0ab849a7e9019c81da24d6" |
||||
+ "daa4f6b2f003d1b0180029")) |
||||
.sender(sender) |
||||
.chainId(2018) |
||||
.privateFrom( |
||||
BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8))) |
||||
.privateFor( |
||||
Lists.newArrayList( |
||||
BytesValue.wrap("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs=".getBytes(UTF_8)))) |
||||
.restriction(BytesValue.wrap("restricted".getBytes(UTF_8))) |
||||
.signAndBuild( |
||||
SECP256K1.KeyPair.create( |
||||
SECP256K1.PrivateKey.create( |
||||
new BigInteger( |
||||
"8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", |
||||
16)))); |
||||
private final Transaction transaction = |
||||
new Transaction( |
||||
privateTransaction.getNonce(), |
||||
privateTransaction.getGasPrice(), |
||||
privateTransaction.getGasLimit(), |
||||
Optional.of(Address.DEFAULT_PRIVACY), |
||||
privateTransaction.getValue(), |
||||
privateTransaction.getSignature(), |
||||
BytesValue.wrap("EnclaveKey".getBytes(UTF_8)), |
||||
privateTransaction.getSender(), |
||||
privateTransaction.getChainId().getAsInt()); |
||||
|
||||
private final Hash hash = |
||||
Hash.fromHexString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); |
||||
private final Hash blockHash = |
||||
Hash.fromHexString("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); |
||||
|
||||
private final JsonRpcParameter parameters = new JsonRpcParameter(); |
||||
|
||||
private final BlockchainQueries blockchainQueries = mock(BlockchainQueries.class); |
||||
private final Blockchain blockchain = mock(Blockchain.class); |
||||
private final Enclave enclave = mock(Enclave.class); |
||||
private final EeaGetTransactionReceipt eeaGetTransactionReceipt = |
||||
new EeaGetTransactionReceipt(blockchainQueries, enclave, parameters); |
||||
Object[] params = new Object[] {transaction.hash(), "EnclavePublicKey"}; |
||||
private final JsonRpcRequest request = |
||||
new JsonRpcRequest("1", "eea_getTransactionReceipt", params); |
||||
|
||||
@Test |
||||
public void createsPrivateTransactionReceipt() throws IOException { |
||||
when(blockchainQueries.getBlockchain()).thenReturn(blockchain); |
||||
when(blockchain.getTransactionByHash(transaction.hash())).thenReturn(Optional.of(transaction)); |
||||
final BytesValueRLPOutput bvrlp = new BytesValueRLPOutput(); |
||||
privateTransaction.writeTo(bvrlp); |
||||
when(enclave.receive(any(ReceiveRequest.class))) |
||||
.thenReturn( |
||||
new ReceiveResponse( |
||||
Base64.getEncoder() |
||||
.encodeToString(bvrlp.encoded().extractArray()) |
||||
.getBytes(UTF_8))); |
||||
|
||||
final JsonRpcSuccessResponse response = |
||||
(JsonRpcSuccessResponse) eeaGetTransactionReceipt.response(request); |
||||
final PrivateTransactionReceiptResult result = |
||||
(PrivateTransactionReceiptResult) response.getResult(); |
||||
|
||||
assertEquals("0x42699a7612a82f1d9c36148af9c77354759b210b", result.getContractAddress()); |
||||
} |
||||
} |
Loading…
Reference in new issue