Skip to content

Commit

Permalink
fix(quorum-connector): integration tests were failing
Browse files Browse the repository at this point in the history
Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
  • Loading branch information
petermetz committed May 19, 2020
1 parent 123d6ee commit 9d8ece1
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 51 deletions.
18 changes: 3 additions & 15 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ version: 2.1
jobs:
build:
environment:
CI_NO_CORDA: false
CI_CONTAINERS_WAIT_TIME: 60
CI_NO_CORDA: 'false'
CI_CONTAINERS_WAIT_TIME: '60'
machine:
image: ubuntu-1604:201903-01
resource_class: xlarge
Expand Down Expand Up @@ -34,19 +34,7 @@ jobs:
- run:
name: Run Hyperledger Cactus CI script
command: |
./packages/core/tools/ci.sh
# Upload test results for display in Test Summary:
# https://circleci.com/docs/2.0/collect-test-data/
- store_test_results:
path: packages/core/examples/simple-asset-transfer/corda/logs/

# Upload test results for display in Artifacts:
# https://circleci.com/docs/2.0/artifacts/
- store_artifacts:
path: packages/core/examples/simple-asset-transfer/corda/logs/
when: always
command: ./tools/ci.sh

workflows:
version: 2
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ services:
- docker

script:
- CI_CONTAINERS_WAIT_TIME=12 CI_NO_CORDA=true ./packages/core/tools/ci.sh
- CI_CONTAINERS_WAIT_TIME=12 CI_NO_CORDA=true ./tools/ci.sh

after_script:
- docker ps -a
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"build:backend": "npm-run-all lint clean generate-sdk tsc webpack",
"build:dev:pkg:cmd-api-server": "lerna exec --stream --scope '*/*api-server' -- 'del-cli dist/** && tsc --project ./tsconfig.json && webpack --env=dev --target=node --config ../../webpack.config.js'",
"build:dev:pkg:test-tooling": "lerna exec --stream --scope '*/*test-tooling' -- 'del-cli dist/** && tsc --project ./tsconfig.json && webpack --env=dev --target=node --config ../../webpack.config.js'",
"build:dev:pkg:bif-plugin-ledger-connector-quorum": "lerna exec --stream --scope '*/*connector-quorum' -- 'del-cli dist/** && tsc --project ./tsconfig.json && webpack --env=dev --target=node --config ../../webpack.config.js'",
"build:dev:pkg:sdk": "lerna exec --stream --scope '*/*sdk' -- 'del-cli dist/** && tsc --project ./tsconfig.json && webpack --env=dev --target=node --config ../../webpack.config.js'",
"webpack": "npm-run-all webpack:web:dev webpack:node:dev webpack:web:prod webpack:node:prod",
"webpack:web:prod": "lerna exec --stream --ignore '*/*{cockpit,server,test-tooling}' -- webpack --env=prod --target=web --config ../../webpack.config.js",
Expand Down
3 changes: 2 additions & 1 deletion packages/bif-plugin-ledger-connector-quorum/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@
"@hyperledger-labs/bif-common": "0.2.0",
"@hyperledger-labs/bif-core-api": "^0.2.0",
"joi": "14.3.1",
"web3": "1.2.7"
"web3": "1.2.7",
"web3-utils": "1.2.7"
},
"devDependencies": {
"@hyperledger-labs/bif-common": "0.2.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { asciiToHex } from 'web3-utils';
import { IPluginLedgerConnector } from '@hyperledger-labs/bif-core-api';
import { Logger, LoggerProvider } from '@hyperledger-labs/bif-common';

import Web3 from 'web3';
import { Contract, ContractSendMethod, ContractOptions, DeployOptions } from 'web3-eth-contract/types/index';
import { Contract, ContractSendMethod, ContractOptions, DeployOptions, SendOptions } from 'web3-eth-contract/types/index';
import { PromiEvent, TransactionReceipt } from 'web3-core/types/index';

export interface IPluginLedgerConnectorQuorumOptions {
Expand All @@ -24,7 +25,7 @@ export class PluginLedgerConnectorQuorum implements IPluginLedgerConnector<any,
}
const web3Provider = new Web3.providers.HttpProvider(this.options.rpcApiHttpHost);
this.web3 = new Web3(web3Provider);
this.log = LoggerProvider.getOrCreate({ label: 'plugin-ledger-connector-quorum' })
this.log = LoggerProvider.getOrCreate({ label: 'plugin-ledger-connector-quorum', level: 'trace' })
}

public async sendTransaction(options: ITransactionOptions): Promise<any> {
Expand All @@ -37,34 +38,76 @@ export class PluginLedgerConnectorQuorum implements IPluginLedgerConnector<any,
}

public async deployContract(options: any): Promise<any> {
const contract: Contract = this.instantiateContract(options.contractJsonArtifact);

const contractSendMethod: ContractSendMethod = contract.deploy({
data: options.contractJsonArtifact.bytecode,
arguments: []
});

const promiEventContract: PromiEvent<Contract> = contractSendMethod.send({
from: options.from || this.web3.eth.defaultAccount,
gas: options.gas || 10000000,
});

promiEventContract
.on('confirmation', (confNumber: number, receipt: TransactionReceipt) => {
this.log.debug(`deployContract() - confirmation: `, { confNumber, receipt });
})
.on('error', (error: Error) => {
this.log.error(`deployContract() - error: `, error);
})
.on('receipt', (receipt: TransactionReceipt) => {
this.log.error(`deployContract() - receipt: `, { receipt });
})
.on('transactionHash', (receipt: string) => {
this.log.error(`deployContract() - transactionHash: `, { receipt });
});

const deployedContract: Contract = await promiEventContract;
this.log.debug(`Successfully deployed contract.`, { deployedContract });
try {
const ethPassword = '';
const unlocked: boolean = await this.web3.eth.personal.unlockAccount(options.from, ethPassword, 3600);
this.log.debug(`Web3 Account unlock outcome: ${unlocked}`);
} catch (ex) {
throw new Error(`PluginLedgerConnectorQuorum#deployContract() failed to unlock account ${options.from}: ${ex.stack}`);
}

const fromAddress = options.from;
const contract: Contract = this.instantiateContract(options.contractJsonArtifact, fromAddress);
this.log.debug(`Instantiated contract OK`);

let nonce: number;
try {
this.log.debug(`Getting transaction count (nonce for account)`);
nonce = await this.web3.eth.getTransactionCount(fromAddress);
this.log.debug(`Transaction count (nonce) acquird OK: ${nonce}`);
} catch (ex) {
throw new Error(`Failed to obtain nonce: ${ex.stack}`);
}

const deployOptions: DeployOptions = {
data: '0x' + options.contractJsonArtifact.bytecode,
};
this.log.debug(`Calling contract deployment...`);
const deployTask: ContractSendMethod = contract.deploy(deployOptions);
this.log.debug(`Called deploy task OK with options: `, { deployOptions });

// try {
// this.log.debug(`Asking ledger for gas estimate...`);
// const gasEstimate = await deployTask.estimateGas({ gas: 5000000, });
// this.log.debug(`Got GasEstimate=${gasEstimate}`);
// // const gas = gasEstimate * 3; // offer triple the gas estimate to be sure
// } catch (ex) {
// throw new Error(`PluginLedgerConnectorQuorum#deployContract() failed to get gas estimate: ${ex.stack}`);
// }

const sendOptions: SendOptions = {
from: fromAddress,
gas: 1500000,
gasPrice: '0',
};

this.log.debug(`Calling send on deploy task...`);
const promiEventContract: PromiEvent<Contract> = deployTask.send(sendOptions);
this.log.debug(`Called send OK with options: `, { sendOptions });

// promiEventContract
// .once('confirmation', (confNumber: number, receipt: TransactionReceipt) => {
// this.log.debug(`deployContract() - confirmation: `, { confNumber, receipt });
// })
// .once('error', (error: Error) => {
// this.log.error(`deployContract() - error: `, error);
// })
// .once('receipt', (receipt: TransactionReceipt) => {
// this.log.debug(`deployContract() - receipt: `, { receipt });
// })
// .once('transactionHash', (receipt: string) => {
// this.log.debug(`deployContract() - transactionHash: `, { receipt });
// });

try {
this.log.debug(`Starting await for contract deployment promise...`);
const deployedContract: Contract = await promiEventContract;
this.log.debug(`Deployed contract OK.`);
return deployedContract;
} catch (ex) {
const message = `PluginLedgerConnectorQuorum#deployContract() Failed to deploy contract: ${ex.stack}`;
throw new Error(message);
}
}

public async addPublicKey(publicKeyHex: string): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,51 @@
// tslint:disable-next-line: no-var-requires
const tap = require('tap');
import { PluginLedgerConnectorQuorum, PluginFactoryLedgerConnector } from '../../../../../main/typescript/public-api';
import { QuorumTestLedger } from '@hyperledger-labs/bif-test-tooling';
import { QuorumTestLedger, IQuorumGenesisOptions, IAccount } from '@hyperledger-labs/bif-test-tooling';
import HelloWorldContractJson from '../../../../solidity/hello-world-contract/HelloWorld.json';
import { Logger, LoggerProvider } from '@hyperledger-labs/bif-common';

const log: Logger = LoggerProvider.getOrCreate({ label: 'test-deploy-contract-from-json', level: 'trace' })

tap.test('deploys contract via .json file', async (assert: any) => {
assert.plan(1);

const quorumTestLedger = new QuorumTestLedger();
const quorumTestLedger = new QuorumTestLedger({ containerImageVersion: '1.0.0' });
await quorumTestLedger.start();

assert.tearDown(async () => {
log.debug(`Starting teardown...`);
await quorumTestLedger.stop();
log.debug(`Stopped container OK.`);
await quorumTestLedger.destroy();
log.debug(`Destroyed container OK.`);
});

// const rpcApiHttpHost: string = 'http://localhost:22000';
const rpcApiHttpHost = await quorumTestLedger.getRpcApiHttpHost();
const quorumGenesisOptions: IQuorumGenesisOptions = await quorumTestLedger.getGenesisJsObject();
assert.ok(quorumGenesisOptions);
assert.ok(quorumGenesisOptions.alloc);

const highNetWorthAccounts: string[] = Object.keys(quorumGenesisOptions.alloc).filter((address: string) => {
const anAccount: IAccount = quorumGenesisOptions.alloc[address];
const balance: number = parseInt(anAccount.balance, 10);
return balance > 10e7;
});
const [firstHighNetWorthAccount] = highNetWorthAccounts;

const factory = new PluginFactoryLedgerConnector();
const connector: PluginLedgerConnectorQuorum = await factory.create({ rpcApiHttpHost });

const options = {
from: firstHighNetWorthAccount, // 0xed9d02e382b34818e88b88a309c7fe71e65f419d from the gensis json alloc property
contractJsonArtifact: HelloWorldContractJson,
// gas: 100000000000,
// gasPrice: 0,
};

const out = await connector.deployContract(options);
assert.ok(out);

assert.end();
log.debug('Assertion ended OK.');
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { ITestLedger } from './i-test-ledger';
export { IKeyPair, isIKeyPair } from './i-key-pair';
export { BesuTestLedger, IBesuTestLedgerConstructorOptions, BESU_TEST_LEDGER_DEFAULT_OPTIONS, BESU_TEST_LEDGER_OPTIONS_JOI_SCHEMA } from './besu/besu-test-ledger';
export { QuorumTestLedger, IQuorumTestLedgerConstructorOptions, QUORUM_TEST_LEDGER_DEFAULT_OPTIONS, QUORUM_TEST_LEDGER_OPTIONS_JOI_SCHEMA } from './quorum/quorum-test-ledger';
export * from './quorum/i-quorum-genesis-options';
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

export interface IAccount {
balance: string;
}

export interface IAllocations {
[key: string]: IAccount;
}

export interface IConfig {
homesteadBlock: number;
byzantiumBlock: number;
constantinopleBlock: number;
chainId: number;
eip150Block: number;
eip155Block: number;
eip150Hash: string;
eip158Block: number;
maxCodeSize: number;
isQuorum: boolean;
}

export interface IQuorumGenesisOptions {
alloc: IAllocations;
coinbase: string;
config: IConfig;
difficulty: string;
extraData: string;
gasLimit: string;
mixhash: string;
nonce: string;
parentHash: string;
timestamp: string;
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { EventEmitter } from 'events';
import { ITestLedger } from "../i-test-ledger";
import { Streams } from '../common/streams';
import { IKeyPair } from '../i-key-pair';
import { IQuorumGenesisOptions } from './i-quorum-genesis-options';

export interface IQuorumTestLedgerConstructorOptions {
containerImageVersion?: string;
Expand Down Expand Up @@ -91,6 +92,11 @@ export class QuorumTestLedger implements ITestLedger {
return { publicKey, privateKey };
}

public async getGenesisJsObject(): Promise<IQuorumGenesisOptions> {
const quorumGenesisJson: string = await this.getFileContents('/genesis.json');
return JSON.parse(quorumGenesisJson);
}

public async getTesseraKeyPair(): Promise<IKeyPair> {
const publicKey = await this.getFileContents('/tm.pub');
const privateKey = await this.getFileContents('/tm.key');
Expand All @@ -110,12 +116,14 @@ export class QuorumTestLedger implements ITestLedger {
await this.pullContainerImage(containerNameAndTag);

return new Promise<Container>((resolve, reject) => {

const eventEmitter: EventEmitter = docker.run(
containerNameAndTag,
[],
[],
{
// Env: [
// 'PRIVATE_CONFIG=ignore'// FIXME make it possible to have privacy configured programmatically for quorum
// ],
ExposedPorts: {
[`${this.rpcApiHttpPort}/tcp`]: {}, // quorum RPC - HTTP
'8546/tcp': {}, // quorum RPC - WebSocket
Expand Down
81 changes: 81 additions & 0 deletions tools/ci.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env bash

###
### Continous Integration Shell Script
###
### Designed to be re-entrant on a local dev machine as well, not just on a
### newly pulled up VM.
###
echo $BASH_VERSION

STARTED_AT=`date +%s`
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
PROJECT_ROOT_DIR="$SCRIPT_DIR/.."

function mainTask()
{
set -euxo pipefail

if ! [ -x "$(command -v lscpu)" ]; then
echo 'lscpu is not installed, skipping...'
else
lscpu
fi

if ! [ -x "$(command -v lsmem)" ]; then
echo 'lsmem is not installed, skipping...'
else
lsmem
fi

if ! [ -x "$(command -v smem)" ]; then
echo 'smem is not installed, skipping...'
else
smem --abbreviate --totals --system
fi

# Travis does not have (nor need) nvm but CircleCI does have nvm and also
# need it big time because their default Node version is 6.x...
if [ "${CIRCLECI:-false}" = "true" ]; then
set +x
nvm install 10.19.0
nvm alias default 10.19.0
set -x
fi

docker --version
docker-compose --version
node --version
npm --version
java -version

### COMMON
cd $PROJECT_ROOT_DIR

npm install
npm run configure
npm run test
npm run test-integration

ENDED_AT=`date +%s`
runtime=$((ENDED_AT-STARTED_AT))
echo "$(date +%FT%T%z) [CI] SUCCESS - runtime=$runtime seconds."
exit 0
}

function onTaskFailure()
{
set +eu # do not crash process upon individual command failures

ENDED_AT=`date +%s`
runtime=$((ENDED_AT-STARTED_AT))
echo "$(date +%FT%T%z) [CI] FAILURE - runtime=$runtime seconds."
exit 1
}

(
mainTask
)
if [ $? -ne 0 ]; then
onTaskFailure
fi

0 comments on commit 9d8ece1

Please sign in to comment.