Skip to content

Commit

Permalink
Fake relayer and unit test for failing segments and root
Browse files Browse the repository at this point in the history
* Check that failures are handled correctly at different parts of the stack
* Change relay test to using fake relayer
  • Loading branch information
drinkcoffee authored Jun 10, 2022
1 parent 2914e83 commit 2bee5c5
Show file tree
Hide file tree
Showing 18 changed files with 548 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@ public static String gen() {
notVeryRandom.nextBytes(rAddress);
return Bytes.wrap(rAddress).toHexString();
}

public static String addressZero() {
return "0";
}
}
62 changes: 62 additions & 0 deletions contracts/contracts/src/functioncall/gpact/FailureTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2021 ConsenSys Software Inc
*
* 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
*/
pragma solidity >=0.8;

import "../../../../../contracts/contracts/src/functioncall/interface/CrosschainFunctionCallInterface.sol";

/**
* Application contract that iteratively calls itself, with parameter driven failures.
* It can be used to test a call trees, selectively failing at a certain call depth or
* at the root of a call tree.
*/
contract FailureTest {
uint256 otherBlockchainId;
FailureTest otherContract;
address cbc;

constructor(
address _crossBlockchainControl,
uint256 _otherBlockchainId,
address _otherContract
) {
cbc = _crossBlockchainControl;
otherBlockchainId = _otherBlockchainId;
otherContract = FailureTest(_otherContract);
}

function callRemote(
uint256 _totalCallDepth,
uint256 _currentCallDepth,
uint256 _whenToFail
) public {
if (_currentCallDepth == _whenToFail) {
revert("Time to Fail!");
}
if (_currentCallDepth == _totalCallDepth) {
return;
}

CrosschainFunctionCallInterface(address(cbc)).crossBlockchainCall(
otherBlockchainId,
address(otherContract),
abi.encodeWithSelector(
otherContract.callRemote.selector,
_totalCallDepth,
_currentCallDepth + 1,
_whenToFail
)
);
}
}
2 changes: 2 additions & 0 deletions contracts/javatest/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
dependencies {
implementation project(':sdk')
implementation project(':common-test')
implementation project (':examples-helpers')


implementation "io.reactivex.rxjava2:rxjava:${rxJavaVersion}"

Expand Down
5 changes: 4 additions & 1 deletion contracts/javatest/gen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ solc $CONTRACTSDIR/application/lockablestorage/TestLockableStorageWrapperAllValu
solc $CONTRACTSDIR/functioncall/interface/HiddenParamDestTest.sol --allow-paths . --bin --abi --hashes --optimize -o $BUILDDIR --overwrite
solc $CONTRACTSDIR/functioncall/interface/HiddenParamSourceTest.sol --allow-paths . --bin --abi --hashes --optimize -o $BUILDDIR --overwrite

solc $CONTRACTSDIR/functioncall/gpact/FailureTest.sol --allow-paths . --bin --abi --hashes --optimize -o $BUILDDIR --overwrite

solc $CONTRACTSDIR/messaging/common/MessagingRegistrar.sol --allow-paths . --bin --abi --hashes --optimize -o $BUILDDIR --overwrite

solc $CONTRACTSDIR/messaging/eventrelay/EventRelayVerifier.sol --allow-paths . --bin --abi --hashes --optimize -o $BUILDDIR --overwrite
Expand All @@ -28,14 +30,15 @@ solc $CONTRACTSDIR/messaging/txrootrelay/TestReceipts.sol --allow-paths . --bin
solc $CONTRACTSDIR/messaging/txrootrelay/TestEvents.sol --allow-paths . --bin --abi --optimize -o $BUILDDIR --overwrite



$WEB3J solidity generate -a=$BUILDDIR/MockCbcForLockableStorageTest.abi -b=$BUILDDIR/MockCbcForLockableStorageTest.bin -o=$OUTPUTDIR -p=$BASEPACKAGE.application.lockablestorage
$WEB3J solidity generate -a=$BUILDDIR/TestLockableStorageWrapper.abi -b=$BUILDDIR/TestLockableStorageWrapper.bin -o=$OUTPUTDIR -p=$BASEPACKAGE.application.lockablestorage
$WEB3J solidity generate -a=$BUILDDIR/TestLockableStorageWrapperAllValues.abi -b=$BUILDDIR/TestLockableStorageWrapperAllValues.bin -o=$OUTPUTDIR -p=$BASEPACKAGE.application.lockablestorage

$WEB3J solidity generate -a=$BUILDDIR/HiddenParamDestTest.abi -b=$BUILDDIR/HiddenParamDestTest.bin -o=$OUTPUTDIR -p=$BASEPACKAGE.functioncall
$WEB3J solidity generate -a=$BUILDDIR/HiddenParamSourceTest.abi -b=$BUILDDIR/HiddenParamSourceTest.bin -o=$OUTPUTDIR -p=$BASEPACKAGE.functioncall

$WEB3J solidity generate -r -a=$BUILDDIR/FailureTest.abi -b=$BUILDDIR/FailureTest.bin -o=$OUTPUTDIR -p=$BASEPACKAGE.functioncall

$WEB3J solidity generate -a=$BUILDDIR/MessagingRegistrar.abi -b=$BUILDDIR/MessagingRegistrar.bin -o=$OUTPUTDIR -p=$BASEPACKAGE.messaging.common

$WEB3J solidity generate -a=$BUILDDIR/EventRelayVerifier.abi -b=$BUILDDIR/EventRelayVerifier.bin -o=$OUTPUTDIR -p=$BASEPACKAGE.messaging.eventrelay
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2022 ConsenSys Software Inc
*
* 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 net.consensys.gpact.functioncall.gpact;

import java.io.IOException;
import java.math.BigInteger;
import net.consensys.gpact.common.AbstractBlockchain;
import net.consensys.gpact.common.BlockchainConfig;
import net.consensys.gpact.common.BlockchainId;
import net.consensys.gpact.functioncall.FailureTest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.web3j.crypto.Credentials;

/**
* Manage the FailureTest contract. This is used as part of tests to check that failures in certain
* parts of the call tree are handled correctly by the GPACT protocol.
*/
public class FailTestContractManager extends AbstractBlockchain {
static final Logger LOG = LogManager.getLogger(FailTestContractManager.class);

String entity;

FailureTest failureTestContract;

public FailTestContractManager(
final String entity, Credentials credentials, final BlockchainConfig bcConfig)
throws IOException {
super(credentials, bcConfig);
this.entity = entity;
}

public void deployContracts(
String cbcContractAddress, BlockchainId otherBlockchainId, String otherContractAddress)
throws Exception {
this.failureTestContract =
FailureTest.deploy(
this.web3j,
this.tm,
this.gasProvider,
cbcContractAddress,
otherBlockchainId.asBigInt(),
otherContractAddress)
.send();
LOG.info(
" Deployed {} contracts: {}", this.entity, this.failureTestContract.getContractAddress());
}

public String contractAddress() {
return this.failureTestContract.getContractAddress();
}

public String getAbi(
BigInteger totalCallDepth, BigInteger currentCallDepth, BigInteger failCallDepth) {
return this.failureTestContract.getABI_callRemote(
totalCallDepth, currentCallDepth, failCallDepth);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
* Copyright 2022 ConsenSys Software.
*
* 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 net.consensys.gpact.functioncall.gpact;

import java.math.BigInteger;
import java.util.ArrayList;
import net.consensys.gpact.common.BlockchainConfig;
import net.consensys.gpact.common.BlockchainId;
import net.consensys.gpact.common.StatsHolder;
import net.consensys.gpact.common.test.DummyAddressGenerator;
import net.consensys.gpact.functioncall.CallExecutionTree;
import net.consensys.gpact.functioncall.CrossControlManagerGroup;
import net.consensys.gpact.functioncall.CrosschainCallResult;
import net.consensys.gpact.helpers.AbstractExampleTest;
import net.consensys.gpact.helpers.CredentialsCreator;
import net.consensys.gpact.helpers.GpactExampleSystemManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import org.web3j.crypto.Credentials;

/**
* Test to check that the GPACT Crosschain Control contract handles failures at the leaf segment,
* intermediate segment, and root of a call execution tree.
*
* <p>The call tree is:
*
* <p>Root -> Intermediate Segment -> Leaf Segment
*/
public class FailedGpactCallTreeTest extends AbstractExampleTest {
static final Logger LOG = LogManager.getLogger(FailedGpactCallTreeTest.class);

GpactExampleSystemManager exampleManager;

FailTestContractManager rootBlockchain;
FailTestContractManager intermediateBlockchain;
FailTestContractManager leafBlockchain;

BlockchainConfig root;
BlockchainConfig bc2;
BlockchainConfig bc3;

CrossControlManagerGroup crossControlManagerGroup;

@Test
public void testFailingRootAndSegments() throws Exception {
try {
deployContracts();

happyCase();
failLeafSegment();
failIntermediateSegment();
failRoot();

} finally {
if (this.rootBlockchain != null) {
this.rootBlockchain.shutdown();
}
if (this.intermediateBlockchain != null) {
this.intermediateBlockchain.shutdown();
}
if (this.leafBlockchain != null) {
leafBlockchain.shutdown();
}

StatsHolder.log("End");
StatsHolder.print();
}
}

private void deployContracts() throws Exception {
LOG.info("****** Deploy Contracts *******");
String tempPropsFile = createPropertiesFile(MessagingType.FAKE, true, false);

this.exampleManager = new GpactExampleSystemManager(tempPropsFile);
exampleManager.standardExampleConfig(3);

this.root = exampleManager.getRootBcInfo();
this.bc2 = exampleManager.getBc2Info();
this.bc3 = exampleManager.getBc3Info();
this.crossControlManagerGroup = exampleManager.getCrossControlManagerGroup();

// Set-up classes to manage blockchains.
Credentials appCreds = CredentialsCreator.createCredentials();
this.rootBlockchain = new FailTestContractManager("root", appCreds, root);
this.intermediateBlockchain = new FailTestContractManager("intermediate", appCreds, bc2);
this.leafBlockchain = new FailTestContractManager("leaf", appCreds, bc3);

// Deploy application contracts.
leafBlockchain.deployContracts(
crossControlManagerGroup.getCbcAddress(bc3.bcId),
BlockchainId.empty(),
DummyAddressGenerator.addressZero());
intermediateBlockchain.deployContracts(
crossControlManagerGroup.getCbcAddress(bc2.bcId),
bc3.bcId,
leafBlockchain.contractAddress());
rootBlockchain.deployContracts(
crossControlManagerGroup.getCbcAddress(root.bcId),
bc2.bcId,
intermediateBlockchain.contractAddress());
}

private void happyCase() throws Exception {
// Specify the call depth for the recursive call to fail to be more than two. This will
// mean that the code will not get to the point of failure.
executeTest("Happy Case", 5, true);
}

private void failLeafSegment() throws Exception {
executeTest("Fail Leaf Segment", 2, false);
}

private void failIntermediateSegment() throws Exception {
executeTest("Fail Intermediate Segment", 1, false);
}

private void failRoot() throws Exception {
executeTest("Fail Root", 0, false);
}

private void executeTest(String testName, int failAtCallDepth, boolean expectToPass)
throws Exception {
LOG.info("****** {} *******", testName);

BigInteger totalCallDepth = BigInteger.TWO;
BigInteger failAtCallDepthBigInt = BigInteger.valueOf(failAtCallDepth);
BigInteger callDepthRoot = BigInteger.ZERO;
BigInteger callDepthIntermediate = BigInteger.ONE;
BigInteger callDepthLeaf = BigInteger.TWO;

ArrayList<CallExecutionTree> intermediateCalls = new ArrayList<>();
ArrayList<CallExecutionTree> rootCalls = new ArrayList<>();
CallExecutionTree leafSeg =
new CallExecutionTree(
bc3.bcId,
leafBlockchain.contractAddress(),
intermediateBlockchain.getAbi(totalCallDepth, callDepthLeaf, failAtCallDepthBigInt));
intermediateCalls.add(leafSeg);
CallExecutionTree intermediateSeg =
new CallExecutionTree(
bc2.bcId,
intermediateBlockchain.contractAddress(),
intermediateBlockchain.getAbi(
totalCallDepth, callDepthIntermediate, failAtCallDepthBigInt),
intermediateCalls);
rootCalls.add(intermediateSeg);
CallExecutionTree rootCall =
new CallExecutionTree(
root.bcId,
rootBlockchain.contractAddress(),
rootBlockchain.getAbi(totalCallDepth, callDepthRoot, failAtCallDepthBigInt),
rootCalls);

CrosschainCallResult result =
crossControlManagerGroup.executeCrosschainCall(
exampleManager.getExecutionEngine(), rootCall, 300);

if (result.isSuccessful() != expectToPass) {
String successStr = expectToPass ? "successful" : "unsuccessful";
throw new Exception(testName + " was unexpectedly " + successStr);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import net.consensys.gpact.functioncall.sfc.SimpleCrosschainControl;
import net.consensys.gpact.messaging.SignedEvent;
import net.consensys.gpact.messaging.common.MessagingRegistrar;
import net.consensys.gpact.messaging.fake.FakeRelayer;
import net.consensys.gpact.messaging.fake.FakeSigner;
import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.Test;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
Expand Down Expand Up @@ -111,22 +113,26 @@ public void executeFunctionCall() throws Exception {
String sourceBcCbcAddress =
"0xF3ce7435e19A4E902e2aF5bfE48a3004DBef0001"; // For the purposes of this test, a random
// address.
EventSigner eventSigner = new EventSigner(sourceBcId);

AnIdentity newSigner = AnIdentity.createNewRandomIdentity();
FakeRelayer fakeRelayer = new FakeRelayer(newSigner);
FakeSigner fakeSigner = new FakeSigner(sourceBcId, fakeRelayer);

setupWeb3();
deployContracts(sourceBcId, sourceBcCbcAddress, destBcId);

AnIdentity newSigner = AnIdentity.createNewRandomIdentity();
addBlockchain(sourceBcId, newSigner.getAddress());
eventSigner.addSigner(newSigner);

BigInteger val = BigInteger.valueOf(17);

byte[] eventData = createEventData(destBcId, val);

SignedEvent signedEvent =
eventSigner.getSignedEvent(
eventData, sourceBcCbcAddress, SimpleCrossControlManager.CROSSCALL_EVENT_SIGNATURE);
fakeSigner.getSignedEvent(
null,
null,
eventData,
sourceBcCbcAddress,
SimpleCrossControlManager.CROSSCALL_EVENT_SIGNATURE);

TransactionReceipt txR;
try {
Expand Down
Loading

0 comments on commit 2bee5c5

Please sign in to comment.