mirror of https://github.com/hyperledger/besu
remove container tests (#4999)
* remove container tests Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> * print error message in event of AT failure Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com>pull/5014/head
parent
6b9c1ce40d
commit
37ffa1f8bf
@ -1,17 +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 |
|
||||||
*/ |
|
||||||
|
|
||||||
jar { enabled = false } |
|
@ -1,40 +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 |
|
||||||
*/ |
|
||||||
|
|
||||||
jar { enabled = false } |
|
||||||
|
|
||||||
dependencies { |
|
||||||
testImplementation 'junit:junit' |
|
||||||
testImplementation 'org.assertj:assertj-core' |
|
||||||
testImplementation 'org.awaitility:awaitility' |
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter' |
|
||||||
testImplementation 'org.testcontainers:testcontainers' |
|
||||||
testImplementation 'org.web3j:core' |
|
||||||
testImplementation 'org.web3j:quorum' |
|
||||||
|
|
||||||
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' |
|
||||||
} |
|
||||||
|
|
||||||
test.enabled = false |
|
||||||
// TODO make this run only on nightly |
|
||||||
task containerTests(type: Test) { |
|
||||||
description = 'Runs GoQuorum <> Besu container tests.' |
|
||||||
dependsOn(rootProject.distDocker) |
|
||||||
def dockerBuildVersion = project.hasProperty('release.releaseVersion') ? project.property('release.releaseVersion') : "${rootProject.version}" |
|
||||||
def imageName = "hyperledger/besu" |
|
||||||
def image = "${imageName}:${dockerBuildVersion}" |
|
||||||
systemProperty 'containertest.imagename', image |
|
||||||
} |
|
@ -1,301 +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.container; |
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.nio.file.Files; |
|
||||||
import java.nio.file.Path; |
|
||||||
import java.util.concurrent.TimeUnit; |
|
||||||
import java.util.function.Consumer; |
|
||||||
|
|
||||||
import com.github.dockerjava.api.command.CreateContainerCmd; |
|
||||||
import org.awaitility.Awaitility; |
|
||||||
import org.awaitility.core.ThrowingRunnable; |
|
||||||
import org.junit.After; |
|
||||||
import org.junit.Before; |
|
||||||
import org.junit.Rule; |
|
||||||
import org.testcontainers.containers.BindMode; |
|
||||||
import org.testcontainers.containers.GenericContainer; |
|
||||||
import org.testcontainers.containers.Network; |
|
||||||
import org.testcontainers.containers.wait.strategy.Wait; |
|
||||||
import org.web3j.crypto.CipherException; |
|
||||||
import org.web3j.crypto.Credentials; |
|
||||||
import org.web3j.protocol.Web3j; |
|
||||||
import org.web3j.protocol.core.methods.response.EthBlockNumber; |
|
||||||
import org.web3j.protocol.core.methods.response.Web3ClientVersion; |
|
||||||
import org.web3j.protocol.http.HttpService; |
|
||||||
import org.web3j.quorum.Quorum; |
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"}) |
|
||||||
public class ContainerTestBase { |
|
||||||
// A docker image can be built using `./gradlew clean distDocker`
|
|
||||||
// check the status of local images with `docker images`
|
|
||||||
// To use that local image, change besuImage below eg
|
|
||||||
// private final String besuImage = "hyperledger/besu:21.7.0-SNAPSHOT";
|
|
||||||
private final String besuImage = System.getProperty("containertest.imagename"); |
|
||||||
|
|
||||||
public static final String GOQUORUM_VERSION = "22.4.4"; |
|
||||||
public static final String TESSERA_VERSION = "22.1.7"; |
|
||||||
|
|
||||||
protected final String goQuorumTesseraPubKey = "3XGBIf+x8IdVQOVfIsbRnHwTYOJP/Fx84G8gMmy8qDM="; |
|
||||||
protected final String besuTesseraPubKey = "8JJLEAbq6o9m4Kqm++v0Y1n9Z2ryAFtZTyhnxSKWgws="; |
|
||||||
|
|
||||||
private final Network containerNetwork = Network.SHARED; |
|
||||||
protected Quorum besuWeb3j; |
|
||||||
protected Quorum goQuorumWeb3j; |
|
||||||
|
|
||||||
// General config
|
|
||||||
private final String hostGenesisPath = "/genesis.json"; |
|
||||||
private final String hostKeyPath = "/keys/"; |
|
||||||
private final String containerKeyPath = "/tmp/keys/"; |
|
||||||
private final Integer networkId = 2020; |
|
||||||
|
|
||||||
// Besu config
|
|
||||||
private final Integer besuP2pPort = 30303; |
|
||||||
private final Integer besuRpcPort = 8545; |
|
||||||
private final String besuContainerGenesisPath = "/opt/besu/genesis.json"; |
|
||||||
private final String besuNetworkAlias = "besuNode"; |
|
||||||
private final String hostBesuKeyPath = "/besu/data/key"; |
|
||||||
private final String containerBesuKeyPath = "/opt/besu/key"; |
|
||||||
|
|
||||||
// GoQuorum + Tessera shared config
|
|
||||||
private final String ipcBindDir = "/tmp/ipc/"; |
|
||||||
private final String ipcDirPath = "/ipc/"; |
|
||||||
private final String ipcFilePath = "test.ipc"; |
|
||||||
private final String containerIpcPath = ipcBindDir + ipcFilePath; |
|
||||||
|
|
||||||
// Tessera config
|
|
||||||
private final String tesseraContainerPrivKey1Path = "/tmp/keys/key1.key"; |
|
||||||
private final String tesseraContainerPubKey1Path = "/tmp/keys/key1.pub"; |
|
||||||
private final String tesseraContainerPrivKey2Path = "/tmp/keys/key2.key"; |
|
||||||
private final String tesseraContainerPubKey2Path = "/tmp/keys/key2.pub"; |
|
||||||
private final String tesseraContainerConfigFilePath = "/tmp/tessera/tesseraConfig.json"; |
|
||||||
protected final int tesseraRestPort = 9081; |
|
||||||
private final int tesseraQ2TRestPort = 9003; |
|
||||||
private final String hostTesseraResources = "/tessera/"; |
|
||||||
private final String containerTesseraResources = "/tmp/tessera/"; |
|
||||||
private final int tesseraP2pPort = 9001; |
|
||||||
|
|
||||||
// GoQuorum config
|
|
||||||
private final String goQuorumContainerDatadir = "/tmp/qdata/"; |
|
||||||
private final String goQuorumContainerGenesis = "/tmp/qdata/genesis.json"; |
|
||||||
private final String goQuorumContainerGethIpcPath = goQuorumContainerDatadir + "/geth.ipc"; |
|
||||||
private final Integer goQuorumP2pPort = 30303; |
|
||||||
private final Integer goQuorumRpcPort = 8545; |
|
||||||
|
|
||||||
@Rule public final GenericContainer besuContainer = buildBesuContainer(); |
|
||||||
|
|
||||||
@Rule |
|
||||||
public final GenericContainer tesseraGoQuorumContainer = |
|
||||||
buildGoQuorumTesseraContainer( |
|
||||||
ipcDirPath, |
|
||||||
ipcBindDir, |
|
||||||
containerIpcPath, |
|
||||||
tesseraContainerPrivKey1Path, |
|
||||||
tesseraContainerPubKey1Path); |
|
||||||
|
|
||||||
@Rule |
|
||||||
public final GenericContainer tesseraBesuContainer = |
|
||||||
buildBesuTesseraContainer(tesseraContainerPrivKey2Path, tesseraContainerPubKey2Path); |
|
||||||
|
|
||||||
@Rule |
|
||||||
public final GenericContainer goQuorumContainer = |
|
||||||
buildGoQuorumContainer(ipcDirPath, ipcBindDir, containerIpcPath); |
|
||||||
|
|
||||||
@Before |
|
||||||
public void setUp() throws IOException, InterruptedException { |
|
||||||
besuWeb3j = |
|
||||||
buildWeb3JQuorum( |
|
||||||
besuContainer.getContainerIpAddress(), besuContainer.getMappedPort(besuRpcPort)); |
|
||||||
goQuorumWeb3j = |
|
||||||
buildWeb3JQuorum( |
|
||||||
goQuorumContainer.getContainerIpAddress(), |
|
||||||
goQuorumContainer.getMappedPort(goQuorumRpcPort)); |
|
||||||
|
|
||||||
waitFor(10, () -> assertClientVersion(besuWeb3j, "besu")); |
|
||||||
waitFor(10, () -> assertClientVersion(goQuorumWeb3j, GOQUORUM_VERSION)); |
|
||||||
|
|
||||||
// Tell GoQuorum to peer to Besu
|
|
||||||
goQuorumContainer.execInContainer( |
|
||||||
"geth", |
|
||||||
"--exec", |
|
||||||
"admin.addPeer(\"enode://11b72d1e2fdde254a493047d4061f3b62cc2ba59f4c1b0cf41dda4ba0d77f0bfe4f932ccf9f60203b1d47753f69edf1c80e755e3159e596b1f6aa03cb0c275c4@" |
|
||||||
+ besuNetworkAlias |
|
||||||
+ ":" |
|
||||||
+ besuP2pPort |
|
||||||
+ "\")", |
|
||||||
"attach", |
|
||||||
goQuorumContainerGethIpcPath); |
|
||||||
|
|
||||||
waitFor(30, () -> assertBlockHeight(besuWeb3j, 5)); |
|
||||||
waitFor(30, () -> assertBlockHeight(goQuorumWeb3j, 5)); |
|
||||||
} |
|
||||||
|
|
||||||
@After |
|
||||||
public void tearDown() throws IOException { |
|
||||||
boolean fileExists = Files.deleteIfExists(Path.of(getResourcePath(ipcDirPath + ipcFilePath))); |
|
||||||
if (!fileExists) { |
|
||||||
System.out.println("Unable to delete tx IPC file."); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private GenericContainer buildBesuContainer() { |
|
||||||
return new GenericContainer(besuImage) |
|
||||||
.withNetwork(containerNetwork) |
|
||||||
.withNetworkAliases(besuNetworkAlias) |
|
||||||
.withExposedPorts(besuRpcPort, besuP2pPort) |
|
||||||
.withClasspathResourceMapping(hostBesuKeyPath, containerBesuKeyPath, BindMode.READ_ONLY) |
|
||||||
.withClasspathResourceMapping(hostGenesisPath, besuContainerGenesisPath, BindMode.READ_ONLY) |
|
||||||
.withClasspathResourceMapping(hostKeyPath, containerKeyPath, BindMode.READ_ONLY) |
|
||||||
.withCommand( |
|
||||||
"--genesis-file", |
|
||||||
besuContainerGenesisPath, |
|
||||||
"--network-id", |
|
||||||
networkId.toString(), |
|
||||||
"--p2p-port", |
|
||||||
besuP2pPort.toString(), |
|
||||||
"--rpc-http-enabled", |
|
||||||
"--rpc-http-port", |
|
||||||
besuRpcPort.toString(), |
|
||||||
"--rpc-http-api", |
|
||||||
"ADMIN,ETH,NET,WEB3,GOQUORUM", |
|
||||||
"--min-gas-price", |
|
||||||
"0", |
|
||||||
"--privacy-public-key-file", |
|
||||||
"/tmp/keys/key2.pub", |
|
||||||
"--privacy-url", |
|
||||||
"http://" + "besuTessera" + ':' + tesseraQ2TRestPort); |
|
||||||
} |
|
||||||
|
|
||||||
private GenericContainer buildGoQuorumTesseraContainer( |
|
||||||
final String ipcPath, |
|
||||||
final String ipcBindDir, |
|
||||||
final String containerIpcPath, |
|
||||||
final String privKeyPath, |
|
||||||
final String pubKeyPath) { |
|
||||||
return new GenericContainer("quorumengineering/tessera:" + TESSERA_VERSION) |
|
||||||
.withNetwork(containerNetwork) |
|
||||||
.withNetworkAliases("goQuorumTessera") |
|
||||||
.withClasspathResourceMapping( |
|
||||||
hostTesseraResources, containerTesseraResources, BindMode.READ_ONLY) |
|
||||||
.withClasspathResourceMapping(ipcPath, ipcBindDir, BindMode.READ_WRITE) |
|
||||||
.withClasspathResourceMapping(hostKeyPath, containerKeyPath, BindMode.READ_ONLY) |
|
||||||
.withCommand( |
|
||||||
"--configfile " + tesseraContainerConfigFilePath, |
|
||||||
"-o serverConfigs[0].serverAddress=http://localhost:" + tesseraRestPort, |
|
||||||
"-o serverConfigs[1].serverAddress=unix:" + containerIpcPath, |
|
||||||
"-o serverConfigs[2].serverAddress=http://" + "goQuorumTessera" + ":" + tesseraP2pPort, |
|
||||||
"-o keys.keyData[0].privateKeyPath=" + privKeyPath, |
|
||||||
"-o keys.keyData[0].publicKeyPath=" + pubKeyPath, |
|
||||||
"-o peer[0].url=http://" + "goQuorumTessera" + ":" + tesseraP2pPort + "/", |
|
||||||
"-o peer[1].url=http://" + "besuTessera" + ":" + tesseraP2pPort + "/") |
|
||||||
.withExposedPorts(tesseraP2pPort, tesseraRestPort) |
|
||||||
.waitingFor(Wait.forHttp("/upcheck")); |
|
||||||
} |
|
||||||
|
|
||||||
private GenericContainer buildBesuTesseraContainer( |
|
||||||
final String privKeyPath, final String pubKeyPath) { |
|
||||||
return new GenericContainer("quorumengineering/tessera:" + TESSERA_VERSION) |
|
||||||
.withNetwork(containerNetwork) |
|
||||||
.withNetworkAliases("besuTessera") |
|
||||||
.withClasspathResourceMapping( |
|
||||||
hostTesseraResources, containerTesseraResources, BindMode.READ_ONLY) |
|
||||||
.withClasspathResourceMapping(hostKeyPath, containerKeyPath, BindMode.READ_ONLY) |
|
||||||
.withCommand( |
|
||||||
"--configfile " + tesseraContainerConfigFilePath, |
|
||||||
"-o serverConfigs[0].serverAddress=http://localhost:" + tesseraRestPort, |
|
||||||
"-o serverConfigs[1].serverAddress=http://localhost:" + tesseraQ2TRestPort, |
|
||||||
"-o serverConfigs[2].serverAddress=http://" + "besuTessera" + ":" + tesseraP2pPort, |
|
||||||
"-o keys.keyData[0].privateKeyPath=" + privKeyPath, |
|
||||||
"-o keys.keyData[0].publicKeyPath=" + pubKeyPath, |
|
||||||
"-o peer[0].url=http://" + "besuTessera" + ":" + tesseraP2pPort + "/", |
|
||||||
"-o peer[1].url=http://" + "goQuorumTessera" + ":" + tesseraP2pPort + "/") |
|
||||||
.withExposedPorts(tesseraP2pPort, tesseraRestPort) |
|
||||||
.waitingFor(Wait.forHttp("/upcheck")); |
|
||||||
} |
|
||||||
|
|
||||||
private GenericContainer buildGoQuorumContainer( |
|
||||||
final String ipcPath, final String ipcBindDir, final String containerIpcPath) { |
|
||||||
return new GenericContainer("quorumengineering/quorum:" + GOQUORUM_VERSION) |
|
||||||
.withNetwork(containerNetwork) |
|
||||||
.dependsOn(tesseraGoQuorumContainer) |
|
||||||
.withExposedPorts(goQuorumRpcPort, goQuorumP2pPort) |
|
||||||
.withClasspathResourceMapping( |
|
||||||
"/goQuorum/qdata/", goQuorumContainerDatadir, BindMode.READ_ONLY) |
|
||||||
.withClasspathResourceMapping(hostGenesisPath, goQuorumContainerGenesis, BindMode.READ_ONLY) |
|
||||||
.withClasspathResourceMapping(ipcPath, ipcBindDir, BindMode.READ_WRITE) |
|
||||||
.withEnv("PRIVATE_CONFIG", containerIpcPath) |
|
||||||
.withCreateContainerCmdModifier( |
|
||||||
(Consumer<CreateContainerCmd>) |
|
||||||
cmd -> |
|
||||||
cmd.withEntrypoint( |
|
||||||
"/bin/ash", |
|
||||||
"-c", |
|
||||||
"geth init " |
|
||||||
+ goQuorumContainerGenesis |
|
||||||
+ " --datadir " |
|
||||||
+ goQuorumContainerDatadir |
|
||||||
+ " && geth --datadir " |
|
||||||
+ goQuorumContainerDatadir |
|
||||||
+ " --networkid " |
|
||||||
+ networkId.toString() |
|
||||||
+ " --rpc" |
|
||||||
+ " --rpcaddr 0.0.0.0" |
|
||||||
+ " --rpcport " |
|
||||||
+ goQuorumRpcPort.toString() |
|
||||||
+ " --rpcapi admin,eth,debug,miner,net,shh,txpool,personal,web3,quorum,quorumExtension,clique" |
|
||||||
+ " --emitcheckpoints" |
|
||||||
+ " --port " |
|
||||||
+ goQuorumP2pPort.toString() |
|
||||||
+ " --verbosity" |
|
||||||
+ " 3" |
|
||||||
+ " --nousb" |
|
||||||
+ " --nodekey " |
|
||||||
+ goQuorumContainerDatadir |
|
||||||
+ "/nodeKey")); |
|
||||||
} |
|
||||||
|
|
||||||
private Quorum buildWeb3JQuorum(final String containerIpAddress, final Integer mappedPort) { |
|
||||||
return Quorum.build(new HttpService("http://" + containerIpAddress + ":" + mappedPort)); |
|
||||||
} |
|
||||||
|
|
||||||
private void assertClientVersion(final Web3j web3, final String clientString) throws IOException { |
|
||||||
final Web3ClientVersion clientVersionResult = web3.web3ClientVersion().send(); |
|
||||||
assertThat(clientVersionResult.getWeb3ClientVersion()).contains(clientString); |
|
||||||
} |
|
||||||
|
|
||||||
private void assertBlockHeight(final Web3j web3j, final int blockHeight) throws IOException { |
|
||||||
final EthBlockNumber blockNumberResult = web3j.ethBlockNumber().send(); |
|
||||||
assertThat(blockNumberResult.getBlockNumber().intValueExact()) |
|
||||||
.isGreaterThanOrEqualTo(blockHeight); |
|
||||||
} |
|
||||||
|
|
||||||
public static void waitFor(final int timeout, final ThrowingRunnable condition) { |
|
||||||
Awaitility.await() |
|
||||||
.ignoreExceptions() |
|
||||||
.atMost(timeout, TimeUnit.SECONDS) |
|
||||||
.untilAsserted(condition); |
|
||||||
} |
|
||||||
|
|
||||||
private String getResourcePath(final String resourceName) { |
|
||||||
return getClass().getResource(resourceName).getPath(); |
|
||||||
} |
|
||||||
|
|
||||||
protected Credentials loadCredentials() throws IOException, CipherException { |
|
||||||
return Credentials.create("8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63"); |
|
||||||
} |
|
||||||
} |
|
@ -1,312 +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.container; |
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat; |
|
||||||
import static org.assertj.core.api.Assertions.assertThatThrownBy; |
|
||||||
import static org.assertj.core.api.Assertions.fail; |
|
||||||
import static org.hyperledger.besu.tests.container.helpers.ContractOperations.deployContractAndReturnAddress; |
|
||||||
import static org.hyperledger.besu.tests.container.helpers.ContractOperations.generate64BytesHexString; |
|
||||||
import static org.hyperledger.besu.tests.container.helpers.ContractOperations.getCode; |
|
||||||
import static org.hyperledger.besu.tests.container.helpers.ContractOperations.getTransactionLog; |
|
||||||
import static org.hyperledger.besu.tests.container.helpers.ContractOperations.sendLogEventAndReturnTransactionHash; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.Arrays; |
|
||||||
import java.util.List; |
|
||||||
import java.util.concurrent.atomic.AtomicBoolean; |
|
||||||
|
|
||||||
import io.reactivex.disposables.Disposable; |
|
||||||
import okhttp3.OkHttpClient; |
|
||||||
import org.jetbrains.annotations.NotNull; |
|
||||||
import org.junit.Before; |
|
||||||
import org.junit.Test; |
|
||||||
import org.web3j.abi.EventEncoder; |
|
||||||
import org.web3j.abi.FunctionReturnDecoder; |
|
||||||
import org.web3j.abi.TypeReference; |
|
||||||
import org.web3j.abi.datatypes.Address; |
|
||||||
import org.web3j.abi.datatypes.Event; |
|
||||||
import org.web3j.abi.datatypes.generated.Int256; |
|
||||||
import org.web3j.crypto.CipherException; |
|
||||||
import org.web3j.crypto.Credentials; |
|
||||||
import org.web3j.protocol.core.DefaultBlockParameterName; |
|
||||||
import org.web3j.protocol.core.methods.request.EthFilter; |
|
||||||
import org.web3j.protocol.core.methods.response.EthLog; |
|
||||||
import org.web3j.protocol.core.methods.response.EthTransaction; |
|
||||||
import org.web3j.protocol.exceptions.TransactionException; |
|
||||||
import org.web3j.quorum.enclave.Enclave; |
|
||||||
import org.web3j.quorum.enclave.Tessera; |
|
||||||
import org.web3j.quorum.enclave.protocol.EnclaveService; |
|
||||||
import org.web3j.quorum.methods.response.PrivatePayload; |
|
||||||
import org.web3j.quorum.tx.QuorumTransactionManager; |
|
||||||
import org.web3j.tx.response.PollingTransactionReceiptProcessor; |
|
||||||
|
|
||||||
public class ContainerTests extends ContainerTestBase { |
|
||||||
|
|
||||||
public static final String CONTRACT_PREFIX = "0x6080604052348015600f57600080fd5b5060"; |
|
||||||
private Credentials credentials; |
|
||||||
private Enclave besuEnclave; |
|
||||||
private EnclaveService besuEnclaveService; |
|
||||||
private Enclave goQuorumEnclave; |
|
||||||
private EnclaveService goQuorumEnclaveService; |
|
||||||
private PollingTransactionReceiptProcessor besuPollingTransactionReceiptProcessor; |
|
||||||
private PollingTransactionReceiptProcessor goQuorumPollingTransactionReceiptProcessor; |
|
||||||
|
|
||||||
@Before |
|
||||||
public void testSetUp() throws IOException, CipherException { |
|
||||||
besuEnclaveService = |
|
||||||
new EnclaveService( |
|
||||||
"http://" + tesseraBesuContainer.getHost(), |
|
||||||
tesseraBesuContainer.getMappedPort(tesseraRestPort), |
|
||||||
new OkHttpClient()); |
|
||||||
besuEnclave = new Tessera(besuEnclaveService, besuWeb3j); |
|
||||||
besuPollingTransactionReceiptProcessor = |
|
||||||
new PollingTransactionReceiptProcessor(besuWeb3j, 1000, 10); |
|
||||||
goQuorumEnclaveService = |
|
||||||
new EnclaveService( |
|
||||||
"http://" + tesseraGoQuorumContainer.getHost(), |
|
||||||
tesseraGoQuorumContainer.getMappedPort(tesseraRestPort), |
|
||||||
new OkHttpClient()); |
|
||||||
goQuorumEnclave = new Tessera(goQuorumEnclaveService, goQuorumWeb3j); |
|
||||||
goQuorumPollingTransactionReceiptProcessor = |
|
||||||
new PollingTransactionReceiptProcessor(goQuorumWeb3j, 1000, 10); |
|
||||||
credentials = loadCredentials(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void contractShouldBeDeployedToBothNodes() throws IOException, TransactionException { |
|
||||||
// create a GoQuorum transaction manager
|
|
||||||
final QuorumTransactionManager qtm = |
|
||||||
new QuorumTransactionManager( |
|
||||||
goQuorumWeb3j, |
|
||||||
goQuorumEnclave, |
|
||||||
credentials, |
|
||||||
goQuorumTesseraPubKey, |
|
||||||
Arrays.asList(goQuorumTesseraPubKey, besuTesseraPubKey)); |
|
||||||
|
|
||||||
// Get the deployed contract address
|
|
||||||
final String contractAddress = |
|
||||||
deployContractAndReturnAddress( |
|
||||||
goQuorumWeb3j, |
|
||||||
credentials, |
|
||||||
qtm, |
|
||||||
besuPollingTransactionReceiptProcessor, |
|
||||||
goQuorumPollingTransactionReceiptProcessor); |
|
||||||
|
|
||||||
// Generate a random value to insert into the log
|
|
||||||
final String logValue = generate64BytesHexString(98765L); |
|
||||||
|
|
||||||
// Send the transaction and get the transaction hash
|
|
||||||
final String transactionHash = |
|
||||||
sendLogEventAndReturnTransactionHash( |
|
||||||
goQuorumWeb3j, |
|
||||||
credentials, |
|
||||||
contractAddress, |
|
||||||
qtm, |
|
||||||
besuPollingTransactionReceiptProcessor, |
|
||||||
goQuorumPollingTransactionReceiptProcessor, |
|
||||||
logValue); |
|
||||||
|
|
||||||
// Get the transaction logs
|
|
||||||
final String goQuorumResult = getTransactionLog(goQuorumWeb3j, transactionHash); |
|
||||||
final String besuResult = getTransactionLog(besuWeb3j, transactionHash); |
|
||||||
|
|
||||||
assertThat(besuResult).isEqualTo(logValue); |
|
||||||
assertThat(goQuorumResult).isEqualTo(logValue); |
|
||||||
|
|
||||||
// Assert the Besu node gets value for eth_getCode
|
|
||||||
final String codeValueBesu = getCode(besuWeb3j, contractAddress); |
|
||||||
assertThat(codeValueBesu).startsWith(CONTRACT_PREFIX); |
|
||||||
|
|
||||||
// Assert the GoQuorum node gets value for eth_getCode
|
|
||||||
final String codeValueGoQuorum = getCode(goQuorumWeb3j, contractAddress); |
|
||||||
assertThat(codeValueGoQuorum).startsWith(CONTRACT_PREFIX); |
|
||||||
assertThat(codeValueBesu).isEqualTo(codeValueGoQuorum); |
|
||||||
|
|
||||||
// Assert that the private payloads returned are the same
|
|
||||||
final String enclaveKey = getEnclaveKey(transactionHash); |
|
||||||
final PrivatePayload goQuorumPayload = goQuorumWeb3j.quorumGetPrivatePayload(enclaveKey).send(); |
|
||||||
final PrivatePayload besuPayload = besuWeb3j.quorumGetPrivatePayload(enclaveKey).send(); |
|
||||||
|
|
||||||
assertThat(goQuorumPayload.getPrivatePayload()).isEqualTo(besuPayload.getPrivatePayload()); |
|
||||||
} |
|
||||||
|
|
||||||
@NotNull |
|
||||||
private String getEnclaveKey(final String transactionHash) throws IOException { |
|
||||||
final EthTransaction send = besuWeb3j.ethGetTransactionByHash(transactionHash).send(); |
|
||||||
return send.getTransaction().get().getInput(); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void contractShouldBeDeployedOnlyToGoQuorumNode() |
|
||||||
throws IOException, TransactionException { |
|
||||||
// create a quorum transaction manager
|
|
||||||
final QuorumTransactionManager qtm = |
|
||||||
new QuorumTransactionManager( |
|
||||||
goQuorumWeb3j, |
|
||||||
goQuorumEnclave, |
|
||||||
credentials, |
|
||||||
goQuorumTesseraPubKey, |
|
||||||
List.of(goQuorumTesseraPubKey)); |
|
||||||
|
|
||||||
// Get the deployed contract address
|
|
||||||
final String contractAddress = |
|
||||||
deployContractAndReturnAddress( |
|
||||||
goQuorumWeb3j, |
|
||||||
credentials, |
|
||||||
qtm, |
|
||||||
goQuorumPollingTransactionReceiptProcessor, |
|
||||||
besuPollingTransactionReceiptProcessor); |
|
||||||
|
|
||||||
// Generate a random value to insert into the log
|
|
||||||
final String logValue = generate64BytesHexString(192837L); |
|
||||||
|
|
||||||
// Send the transaction and get the transaction hash
|
|
||||||
final String transactionHash = |
|
||||||
sendLogEventAndReturnTransactionHash( |
|
||||||
goQuorumWeb3j, |
|
||||||
credentials, |
|
||||||
contractAddress, |
|
||||||
qtm, |
|
||||||
goQuorumPollingTransactionReceiptProcessor, |
|
||||||
besuPollingTransactionReceiptProcessor, |
|
||||||
logValue); |
|
||||||
|
|
||||||
// Assert the GoQuorum node has received the log
|
|
||||||
final String quorumResult = getTransactionLog(goQuorumWeb3j, transactionHash); |
|
||||||
assertThat(quorumResult).isEqualTo(logValue); |
|
||||||
|
|
||||||
// Assert the Besu node has not received the log
|
|
||||||
assertThatThrownBy(() -> getTransactionLog(besuWeb3j, transactionHash)) |
|
||||||
.hasMessageContaining("No log found"); |
|
||||||
|
|
||||||
// Assert the GoQuorum node gets value for eth_getCode
|
|
||||||
final String codeValueGoQuorum = getCode(goQuorumWeb3j, contractAddress); |
|
||||||
assertThat(codeValueGoQuorum).startsWith(CONTRACT_PREFIX); |
|
||||||
|
|
||||||
// Assert the Besu node gets NO value for eth_getCode
|
|
||||||
final String codeValueBesu = getCode(besuWeb3j, contractAddress); |
|
||||||
assertThat(codeValueBesu).isEqualTo("0x"); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void contractShouldBeDeployedOnlyToBesuNode() |
|
||||||
throws IOException, TransactionException, InterruptedException { |
|
||||||
// create a GoQuorum transaction manager
|
|
||||||
final QuorumTransactionManager qtm = |
|
||||||
new QuorumTransactionManager( |
|
||||||
besuWeb3j, besuEnclave, credentials, besuTesseraPubKey, List.of(besuTesseraPubKey)); |
|
||||||
|
|
||||||
// Get the deployed contract address
|
|
||||||
final String contractAddress = |
|
||||||
deployContractAndReturnAddress( |
|
||||||
besuWeb3j, |
|
||||||
credentials, |
|
||||||
qtm, |
|
||||||
besuPollingTransactionReceiptProcessor, |
|
||||||
goQuorumPollingTransactionReceiptProcessor); |
|
||||||
|
|
||||||
// Subscribe to the event
|
|
||||||
final Event testEvent = |
|
||||||
new Event( |
|
||||||
"TestEvent", |
|
||||||
Arrays.<TypeReference<?>>asList( |
|
||||||
new TypeReference<Address>(true) {}, new TypeReference<Int256>() {})); |
|
||||||
final String eventEncoded = EventEncoder.encode(testEvent); |
|
||||||
|
|
||||||
final EthFilter ethFilterSubscription = |
|
||||||
new EthFilter( |
|
||||||
DefaultBlockParameterName.LATEST, DefaultBlockParameterName.LATEST, contractAddress); |
|
||||||
ethFilterSubscription.addSingleTopic(eventEncoded); |
|
||||||
|
|
||||||
// Generate a value to insert into the log
|
|
||||||
final String logValue = generate64BytesHexString(1234567L); |
|
||||||
|
|
||||||
final AtomicBoolean checked = new AtomicBoolean(false); |
|
||||||
final Disposable subscribe = |
|
||||||
besuWeb3j |
|
||||||
.ethLogFlowable(ethFilterSubscription) |
|
||||||
.subscribe( |
|
||||||
log -> { |
|
||||||
final String eventHash = |
|
||||||
log.getTopics().get(0); // Index 0 is the event definition hash
|
|
||||||
|
|
||||||
if (eventHash.equals(eventEncoded)) { |
|
||||||
// address indexed _arg1
|
|
||||||
final Address arg1 = |
|
||||||
(Address) |
|
||||||
FunctionReturnDecoder.decodeIndexedValue( |
|
||||||
log.getTopics().get(1), new TypeReference<Address>() {}); |
|
||||||
assertThat(arg1.toString()).isEqualTo(credentials.getAddress()); |
|
||||||
|
|
||||||
final String data = log.getData(); |
|
||||||
assertThat(data.substring(2)).isEqualTo(logValue); |
|
||||||
|
|
||||||
checked.set(true); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
// Send the transaction and get the transaction hash
|
|
||||||
final String transactionHash = |
|
||||||
sendLogEventAndReturnTransactionHash( |
|
||||||
besuWeb3j, |
|
||||||
credentials, |
|
||||||
contractAddress, |
|
||||||
qtm, |
|
||||||
besuPollingTransactionReceiptProcessor, |
|
||||||
goQuorumPollingTransactionReceiptProcessor, |
|
||||||
logValue); |
|
||||||
|
|
||||||
// Assert the GoQuorum node gets NO value for eth_getCode
|
|
||||||
final String codeValueGoQuorum = getCode(goQuorumWeb3j, contractAddress); |
|
||||||
assertThat(codeValueGoQuorum).isEqualTo("0x"); |
|
||||||
|
|
||||||
// Assert the Besu node gets a value for eth_getCode
|
|
||||||
final String codeValueBesu = getCode(besuWeb3j, contractAddress); |
|
||||||
assertThat(codeValueBesu).startsWith(CONTRACT_PREFIX); |
|
||||||
|
|
||||||
int secondsWaited = 0; |
|
||||||
while (!checked.get()) { |
|
||||||
Thread.sleep(1000); |
|
||||||
secondsWaited++; |
|
||||||
if (secondsWaited > 30) { |
|
||||||
fail("Waited more than 30 seconds for log."); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
subscribe.dispose(); |
|
||||||
|
|
||||||
// Assert the Besu node has received the log
|
|
||||||
final String besuResult = getTransactionLog(besuWeb3j, transactionHash); |
|
||||||
assertThat(besuResult).isEqualTo(logValue); |
|
||||||
|
|
||||||
// Assert the GoQuorum node has not received the log
|
|
||||||
assertThatThrownBy(() -> getTransactionLog(goQuorumWeb3j, transactionHash)) |
|
||||||
.hasMessageContaining("No log found"); |
|
||||||
|
|
||||||
// Get transaction log using a filter
|
|
||||||
final EthFilter ethFilter = |
|
||||||
new EthFilter( |
|
||||||
DefaultBlockParameterName.EARLIEST, DefaultBlockParameterName.LATEST, contractAddress); |
|
||||||
ethFilter.addSingleTopic(eventEncoded); |
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes") |
|
||||||
final List<EthLog.LogResult> logs = besuWeb3j.ethGetLogs(ethFilter).send().getLogs(); |
|
||||||
|
|
||||||
assertThat(logs.size()).isEqualTo(1); |
|
||||||
assertThat(logs.toString()).contains(transactionHash); |
|
||||||
assertThat(logs.toString()).contains(logValue); |
|
||||||
} |
|
||||||
} |
|
@ -1,186 +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.container.helpers; |
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.math.BigInteger; |
|
||||||
import java.util.Collections; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull; |
|
||||||
import org.web3j.abi.FunctionEncoder; |
|
||||||
import org.web3j.crypto.Credentials; |
|
||||||
import org.web3j.crypto.RawTransaction; |
|
||||||
import org.web3j.protocol.core.DefaultBlockParameter; |
|
||||||
import org.web3j.protocol.core.DefaultBlockParameterName; |
|
||||||
import org.web3j.protocol.core.methods.response.EthGetCode; |
|
||||||
import org.web3j.protocol.core.methods.response.EthGetTransactionCount; |
|
||||||
import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt; |
|
||||||
import org.web3j.protocol.core.methods.response.EthSendTransaction; |
|
||||||
import org.web3j.protocol.core.methods.response.Log; |
|
||||||
import org.web3j.protocol.core.methods.response.TransactionReceipt; |
|
||||||
import org.web3j.protocol.exceptions.TransactionException; |
|
||||||
import org.web3j.quorum.Quorum; |
|
||||||
import org.web3j.quorum.tx.QuorumTransactionManager; |
|
||||||
import org.web3j.tx.response.PollingTransactionReceiptProcessor; |
|
||||||
|
|
||||||
public class ContractOperations { |
|
||||||
|
|
||||||
public static final String SIMPLE_STORAGE_CONTRACT_BYTECODE = |
|
||||||
"6080604052348015600f57600080fd5b5060de8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060275760003560e01c8062f88abf14602c575b600080fd5b605560048036036020811015604057600080fd5b81019080803590602001909291905050506057565b005b3373ffffffffffffffffffffffffffffffffffffffff167f748aa07c80b05bd067e3688dbb79d9f9583cd018be6a589a7c364cacd770e0a2826040518082815260200191505060405180910390a25056fea26469706673582212207df0d3ad8bced04b7bd476cc81a6233c0b575966c29b4af96450313628ee623964736f6c63430007040033"; |
|
||||||
public static String SIMPLE_STORAGE_CONTRACT_WITH_CONSTRUCTOR; |
|
||||||
|
|
||||||
public static String deployContractAndReturnAddress( |
|
||||||
final Quorum quorumWeb3j, |
|
||||||
final Credentials credentials, |
|
||||||
final QuorumTransactionManager qtm, |
|
||||||
final PollingTransactionReceiptProcessor pollingTransactionReceiptProcessorReturn, |
|
||||||
final PollingTransactionReceiptProcessor pollingTransactionReceiptProcessorIgnore) |
|
||||||
throws IOException, TransactionException { |
|
||||||
// Build smart contract transaction
|
|
||||||
final String encodedConstructor = FunctionEncoder.encodeConstructor(Collections.emptyList()); |
|
||||||
SIMPLE_STORAGE_CONTRACT_WITH_CONSTRUCTOR = |
|
||||||
SIMPLE_STORAGE_CONTRACT_BYTECODE + encodedConstructor; |
|
||||||
|
|
||||||
final RawTransaction contractTransaction = |
|
||||||
RawTransaction.createTransaction( |
|
||||||
BigInteger.valueOf(getNonce(quorumWeb3j, credentials)), |
|
||||||
BigInteger.ZERO, |
|
||||||
BigInteger.valueOf(4300000), |
|
||||||
"", |
|
||||||
BigInteger.ZERO, |
|
||||||
SIMPLE_STORAGE_CONTRACT_WITH_CONSTRUCTOR); |
|
||||||
|
|
||||||
// Send the signed transaction to quorum
|
|
||||||
final EthSendTransaction sendContractTransactionResult = qtm.signAndSend(contractTransaction); |
|
||||||
assertThat(sendContractTransactionResult.hasError()).isFalse(); |
|
||||||
|
|
||||||
pollNodeForTransactionReceipt( |
|
||||||
pollingTransactionReceiptProcessorIgnore, |
|
||||||
sendContractTransactionResult.getTransactionHash()); |
|
||||||
|
|
||||||
// Poll for the transaction receipt
|
|
||||||
final TransactionReceipt transactionReceiptResult = |
|
||||||
pollNodeForTransactionReceiptResult( |
|
||||||
pollingTransactionReceiptProcessorReturn, |
|
||||||
sendContractTransactionResult.getTransactionHash()); |
|
||||||
|
|
||||||
return transactionReceiptResult.getContractAddress(); |
|
||||||
} |
|
||||||
|
|
||||||
public static String getCode(final Quorum web3j, final String contractAddress) |
|
||||||
throws IOException { |
|
||||||
final DefaultBlockParameter blockParam = |
|
||||||
DefaultBlockParameter.valueOf(DefaultBlockParameterName.LATEST.toString()); |
|
||||||
final EthGetCode codeResult = web3j.ethGetCode(contractAddress, blockParam).send(); |
|
||||||
assertThat(codeResult.getCode()) |
|
||||||
.withFailMessage("Code for contractAddress not found.") |
|
||||||
.isNotEmpty(); |
|
||||||
return codeResult.getCode(); |
|
||||||
} |
|
||||||
|
|
||||||
public static String getTransactionLog(final Quorum web3j, final String transactionHash) |
|
||||||
throws IOException { |
|
||||||
final EthGetTransactionReceipt transactionReceiptResult = |
|
||||||
web3j.ethGetTransactionReceipt(transactionHash).send(); |
|
||||||
assertThat(transactionReceiptResult.getTransactionReceipt()) |
|
||||||
.withFailMessage("Transaction for log not found.") |
|
||||||
.isNotEmpty(); |
|
||||||
final List<Log> logs = transactionReceiptResult.getTransactionReceipt().get().getLogs(); |
|
||||||
assertThat(logs.size()).withFailMessage("No log found.").isEqualTo(1); |
|
||||||
// Remove the 0x prefix
|
|
||||||
return logs.get(0).getData().substring(2); |
|
||||||
} |
|
||||||
|
|
||||||
public static String sendLogEventAndReturnTransactionHash( |
|
||||||
final Quorum quorum, |
|
||||||
final Credentials credentials, |
|
||||||
final String contractAddress, |
|
||||||
final QuorumTransactionManager qtm, |
|
||||||
final PollingTransactionReceiptProcessor pollingTransactionReceiptProcessorReturn, |
|
||||||
final PollingTransactionReceiptProcessor pollingTransactionReceiptProcessorIgnore, |
|
||||||
final String param) |
|
||||||
throws IOException, TransactionException { |
|
||||||
final String functionSig = "0x00f88abf"; |
|
||||||
final String data = functionSig + param; |
|
||||||
final RawTransaction logEventTransaction = |
|
||||||
RawTransaction.createTransaction( |
|
||||||
BigInteger.valueOf(getNonce(quorum, credentials)), |
|
||||||
BigInteger.ZERO, |
|
||||||
BigInteger.valueOf(4300000), |
|
||||||
contractAddress, |
|
||||||
BigInteger.ZERO, |
|
||||||
data); |
|
||||||
|
|
||||||
final EthSendTransaction sendTransactionResult = qtm.signAndSend(logEventTransaction); |
|
||||||
assertThat(sendTransactionResult.hasError()).isFalse(); |
|
||||||
|
|
||||||
pollNodeForTransactionReceipt( |
|
||||||
pollingTransactionReceiptProcessorIgnore, sendTransactionResult.getTransactionHash()); |
|
||||||
|
|
||||||
final TransactionReceipt logReceiptResult = |
|
||||||
pollNodeForTransactionReceiptResult( |
|
||||||
pollingTransactionReceiptProcessorReturn, sendTransactionResult.getTransactionHash()); |
|
||||||
|
|
||||||
return logReceiptResult.getTransactionHash(); |
|
||||||
} |
|
||||||
|
|
||||||
public static String generate64BytesHexString(final long number) { |
|
||||||
final String str = Long.toHexString(number); |
|
||||||
|
|
||||||
return prependZeroesToPadHexStringToGivenLength(str, 64); |
|
||||||
} |
|
||||||
|
|
||||||
@NotNull |
|
||||||
public static String prependZeroesToPadHexStringToGivenLength( |
|
||||||
final String hexString, final int lenRequested) { |
|
||||||
final StringBuilder sb = new StringBuilder(hexString); |
|
||||||
while (sb.length() < lenRequested) { |
|
||||||
sb.insert(0, '0'); |
|
||||||
} |
|
||||||
return sb.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
public static int getNonce(final Quorum quorum, final Credentials credentials) |
|
||||||
throws IOException { |
|
||||||
final EthGetTransactionCount transactionCountResult = |
|
||||||
quorum |
|
||||||
.ethGetTransactionCount(credentials.getAddress(), DefaultBlockParameterName.LATEST) |
|
||||||
.send(); |
|
||||||
assertThat(transactionCountResult.hasError()).isFalse(); |
|
||||||
return transactionCountResult.getTransactionCount().intValueExact(); |
|
||||||
} |
|
||||||
|
|
||||||
public static TransactionReceipt pollNodeForTransactionReceiptResult( |
|
||||||
final PollingTransactionReceiptProcessor pollingTransactionReceiptProcessor, |
|
||||||
final String transactionHash) |
|
||||||
throws IOException, TransactionException { |
|
||||||
final TransactionReceipt transactionReceiptResult = |
|
||||||
pollingTransactionReceiptProcessor.waitForTransactionReceipt(transactionHash); |
|
||||||
assertThat(transactionReceiptResult.isStatusOK()).isTrue(); |
|
||||||
return transactionReceiptResult; |
|
||||||
} |
|
||||||
|
|
||||||
public static void pollNodeForTransactionReceipt( |
|
||||||
final PollingTransactionReceiptProcessor pollingTransactionReceiptProcessor, |
|
||||||
final String transactionHash) |
|
||||||
throws IOException, TransactionException { |
|
||||||
final TransactionReceipt transactionReceiptResult = |
|
||||||
pollingTransactionReceiptProcessor.waitForTransactionReceipt(transactionHash); |
|
||||||
assertThat(transactionReceiptResult.isStatusOK()).isTrue(); |
|
||||||
} |
|
||||||
} |
|
@ -1 +0,0 @@ |
|||||||
0x8a15eaa6e526e9b8ebdea0bfc6d4399b0ae7ba1c |
|
@ -1 +0,0 @@ |
|||||||
0xc86c0030a86bb894c1e10c25d48d4949a288df9c6ff736b32d977f39893fd0dc |
|
@ -1,45 +0,0 @@ |
|||||||
{ |
|
||||||
"config":{ |
|
||||||
"homesteadBlock": 0, |
|
||||||
"byzantiumBlock": 0, |
|
||||||
"constantinopleBlock": 0, |
|
||||||
"chainId":2020, |
|
||||||
"eip150Block": 0, |
|
||||||
"eip155Block": 0, |
|
||||||
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", |
|
||||||
"eip158Block": 0, |
|
||||||
"clique":{ |
|
||||||
"blockperiodseconds":2, |
|
||||||
"epochlength":30000, |
|
||||||
"period": 2, |
|
||||||
"epoch": 30000 |
|
||||||
}, |
|
||||||
"isQuorum": true |
|
||||||
}, |
|
||||||
"coinbase":"0x0000000000000000000000000000000000000000", |
|
||||||
|
|
||||||
"extraData":"0x00000000000000000000000000000000000000000000000000000000000000008a15eaa6e526e9b8ebdea0bfc6d4399b0ae7ba1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", |
|
||||||
"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" |
|
||||||
} |
|
||||||
}, |
|
||||||
"difficulty": "0x0", |
|
||||||
"gasLimit": "0xE0000000", |
|
||||||
"mixhash": "0x00000000000000000000000000000000000000647572616c65787365646c6578", |
|
||||||
"nonce": "0x0", |
|
||||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", |
|
||||||
"timestamp": "0x00" |
|
||||||
} |
|
@ -1 +0,0 @@ |
|||||||
c0b7ff2352175d2a43d72eca7c2f806cc7bd74a7a597630d62f5261834348f74 |
|
@ -1,6 +0,0 @@ |
|||||||
{ |
|
||||||
"type" : "unlocked", |
|
||||||
"data" : { |
|
||||||
"bytes" : "srn2w10NWdvWyHkPMWB07W5NjIPmiAHRqESL8vH3Kyw=" |
|
||||||
} |
|
||||||
} |
|
@ -1 +0,0 @@ |
|||||||
3XGBIf+x8IdVQOVfIsbRnHwTYOJP/Fx84G8gMmy8qDM= |
|
@ -1,6 +0,0 @@ |
|||||||
{ |
|
||||||
"type" : "unlocked", |
|
||||||
"data" : { |
|
||||||
"bytes" : "LWjzMnDP/MQIATegt45LTrMh1i9ISX64CFO0EzFDNhg=" |
|
||||||
} |
|
||||||
} |
|
@ -1 +0,0 @@ |
|||||||
8JJLEAbq6o9m4Kqm++v0Y1n9Z2ryAFtZTyhnxSKWgws= |
|
@ -1,47 +0,0 @@ |
|||||||
{ |
|
||||||
"useWhiteList": false, |
|
||||||
"jdbc": { |
|
||||||
"username": "sa", |
|
||||||
"password": "", |
|
||||||
"url": "jdbc:h2:/tmp/tessera;LOCK_TIMEOUT=20000", |
|
||||||
"autoCreateTables": true |
|
||||||
}, |
|
||||||
"serverConfigs":[ |
|
||||||
{ |
|
||||||
"app":"ThirdParty", |
|
||||||
"enabled": true, |
|
||||||
"serverAddress": "http://localhost:9081", |
|
||||||
"communicationType" : "REST" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"app":"Q2T", |
|
||||||
"enabled": true, |
|
||||||
"serverAddress": "unix:/tmp/test.ipc", |
|
||||||
"communicationType" : "REST" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"app":"P2P", |
|
||||||
"enabled": true, |
|
||||||
"serverAddress":"http://localhost:9001", |
|
||||||
"sslConfig": { |
|
||||||
"tls": "OFF" |
|
||||||
}, |
|
||||||
"communicationType" : "REST" |
|
||||||
} |
|
||||||
], |
|
||||||
"peer": [ |
|
||||||
{ |
|
||||||
"url": "http://localhost:9001" |
|
||||||
} |
|
||||||
], |
|
||||||
"keys": { |
|
||||||
"passwords": [], |
|
||||||
"keyData": [ |
|
||||||
{ |
|
||||||
"privateKeyPath": "myKey.key", |
|
||||||
"publicKeyPath": "myKey.pub" |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"alwaysSendTo": [] |
|
||||||
} |
|
@ -1,9 +0,0 @@ |
|||||||
pragma solidity >=0.6.0 < 0.8.0; |
|
||||||
|
|
||||||
contract TestContract { |
|
||||||
event TestEvent(address indexed _from, int val); |
|
||||||
|
|
||||||
function logEvent(int randomNum) public { |
|
||||||
emit TestEvent(msg.sender, randomNum); |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue