Skip to content

Commit

Permalink
feat(connector): remove keychain dependency
Browse files Browse the repository at this point in the history
    Primary Changes
    ---------------
    1. Updated besu, ethereum, quorum and xdai connectors
    to remove hard dependencies on keychain

    Changes required to incorporate 1)
    2. Updated openapi.json file of the above mentioned connectors
       to include the new no-keychain endpoints
    3. Generated code and updated related web-services for the same

Fixes hyperledger-cacti#963

Signed-off-by: jagpreetsinghsasan <jagpreet.singh.sasan@accenture.com>
  • Loading branch information
jagpreetsinghsasan committed Apr 3, 2024
1 parent db3fe87 commit 1319363
Show file tree
Hide file tree
Showing 33 changed files with 1,472 additions and 267 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,73 @@
}
}
},
"DeployContractSolidityBytecodeNoKeychainV1Request": {
"type": "object",
"required": [
"contractName",
"contractAbi",
"contractJson",
"bytecode",
"web3SigningCredential",
"keychainId",
"constructorArgs"
],
"additionalProperties": false,
"properties": {
"contractName": {
"type": "string",
"description": "The contract name for retrieve the contracts json on the keychain.",
"minLength": 1,
"maxLength": 100,
"nullable": false
},
"contractAbi": {
"description": "The application binary interface of the solidity contract",
"type": "array",
"items": {},
"nullable": false
},
"contractJSONString": {
"description": "For use when not using keychain, pass the contract in as this string variable",
"nullable": false,
"type": "string"
},
"constructorArgs": {
"type": "array",
"items": {},
"default": []
},
"web3SigningCredential": {
"$ref": "#/components/schemas/Web3SigningCredential",
"nullable": false
},
"bytecode": {
"type": "string",
"nullable": false,
"minLength": 1,
"maxLength": 24576,
"description": "See https://ethereum.stackexchange.com/a/47556 regarding the maximum length of the bytecode"
},
"gas": {
"type": "number",
"nullable": false
},
"gasPrice": {
"type": "string",
"nullable": false
},
"timeoutMs": {
"type": "number",
"description": "The amount of milliseconds to wait for a transaction receipt with theaddress of the contract(which indicates successful deployment) beforegiving up and crashing.",
"minimum": 0,
"default": 60000,
"nullable": false
},
"privateTransactionConfig": {
"$ref": "#/components/schemas/BesuPrivateTransactionConfig"
}
}
},
"DeployContractSolidityBytecodeV1Response": {
"type": "object",
"required": ["transactionReceipt"],
Expand Down Expand Up @@ -1007,6 +1074,40 @@
}
}
},
"/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-besu/deploy-contract-solidity-bytecode-no-keychain": {
"post": {
"x-hyperledger-cacti": {
"http": {
"verbLowerCase": "post",
"path": "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-besu/deploy-contract-solidity-bytecode-no-keychain"
}
},
"operationId": "deployContractSolBytecodeNoKeychainV1",
"summary": "Deploys the bytecode of a Solidity contract without the need of keychain",
"parameters": [],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeployContractSolidityBytecodeNoKeychainV1Request"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeployContractSolidityBytecodeV1Response"
}
}
}
}
}
}
},
"/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-besu/get-balance": {
"post": {
"x-hyperledger-cacti": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,73 @@ export interface ConsistencyStrategy {
}


/**
*
* @export
* @interface DeployContractSolidityBytecodeNoKeychainV1Request
*/
export interface DeployContractSolidityBytecodeNoKeychainV1Request {
/**
* The contract name for retrieve the contracts json on the keychain.
* @type {string}
* @memberof DeployContractSolidityBytecodeNoKeychainV1Request
*/
'contractName': string;
/**
* The application binary interface of the solidity contract
* @type {Array<any>}
* @memberof DeployContractSolidityBytecodeNoKeychainV1Request
*/
'contractAbi': Array<any>;
/**
* For use when not using keychain, pass the contract in as this string variable
* @type {string}
* @memberof DeployContractSolidityBytecodeNoKeychainV1Request
*/
'contractJSONString'?: string;
/**
*
* @type {Array<any>}
* @memberof DeployContractSolidityBytecodeNoKeychainV1Request
*/
'constructorArgs': Array<any>;
/**
*
* @type {Web3SigningCredential}
* @memberof DeployContractSolidityBytecodeNoKeychainV1Request
*/
'web3SigningCredential': Web3SigningCredential;
/**
* See https://ethereum.stackexchange.com/a/47556 regarding the maximum length of the bytecode
* @type {string}
* @memberof DeployContractSolidityBytecodeNoKeychainV1Request
*/
'bytecode': string;
/**
*
* @type {number}
* @memberof DeployContractSolidityBytecodeNoKeychainV1Request
*/
'gas'?: number;
/**
*
* @type {string}
* @memberof DeployContractSolidityBytecodeNoKeychainV1Request
*/
'gasPrice'?: string;
/**
* The amount of milliseconds to wait for a transaction receipt with theaddress of the contract(which indicates successful deployment) beforegiving up and crashing.
* @type {number}
* @memberof DeployContractSolidityBytecodeNoKeychainV1Request
*/
'timeoutMs'?: number;
/**
*
* @type {BesuPrivateTransactionConfig}
* @memberof DeployContractSolidityBytecodeNoKeychainV1Request
*/
'privateTransactionConfig'?: BesuPrivateTransactionConfig;
}
/**
*
* @export
Expand Down Expand Up @@ -1287,6 +1354,40 @@ export interface Web3TransactionReceipt {
*/
export const DefaultApiAxiosParamCreator = function (configuration?: Configuration) {
return {
/**
*
* @summary Deploys the bytecode of a Solidity contract without the need of keychain
* @param {DeployContractSolidityBytecodeNoKeychainV1Request} [deployContractSolidityBytecodeNoKeychainV1Request]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
deployContractSolBytecodeNoKeychainV1: async (deployContractSolidityBytecodeNoKeychainV1Request?: DeployContractSolidityBytecodeNoKeychainV1Request, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-besu/deploy-contract-solidity-bytecode-no-keychain`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}

const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;



localVarHeaderParameter['Content-Type'] = 'application/json';

setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(deployContractSolidityBytecodeNoKeychainV1Request, localVarRequestOptions, configuration)

return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @summary Deploys the bytecode of a Solidity contract.
Expand Down Expand Up @@ -1665,6 +1766,17 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati
export const DefaultApiFp = function(configuration?: Configuration) {
const localVarAxiosParamCreator = DefaultApiAxiosParamCreator(configuration)
return {
/**
*
* @summary Deploys the bytecode of a Solidity contract without the need of keychain
* @param {DeployContractSolidityBytecodeNoKeychainV1Request} [deployContractSolidityBytecodeNoKeychainV1Request]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async deployContractSolBytecodeNoKeychainV1(deployContractSolidityBytecodeNoKeychainV1Request?: DeployContractSolidityBytecodeNoKeychainV1Request, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<DeployContractSolidityBytecodeV1Response>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.deployContractSolBytecodeNoKeychainV1(deployContractSolidityBytecodeNoKeychainV1Request, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @summary Deploys the bytecode of a Solidity contract.
Expand Down Expand Up @@ -1794,6 +1906,16 @@ export const DefaultApiFp = function(configuration?: Configuration) {
export const DefaultApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
const localVarFp = DefaultApiFp(configuration)
return {
/**
*
* @summary Deploys the bytecode of a Solidity contract without the need of keychain
* @param {DeployContractSolidityBytecodeNoKeychainV1Request} [deployContractSolidityBytecodeNoKeychainV1Request]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
deployContractSolBytecodeNoKeychainV1(deployContractSolidityBytecodeNoKeychainV1Request?: DeployContractSolidityBytecodeNoKeychainV1Request, options?: any): AxiosPromise<DeployContractSolidityBytecodeV1Response> {
return localVarFp.deployContractSolBytecodeNoKeychainV1(deployContractSolidityBytecodeNoKeychainV1Request, options).then((request) => request(axios, basePath));
},
/**
*
* @summary Deploys the bytecode of a Solidity contract.
Expand Down Expand Up @@ -1912,6 +2034,18 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa
* @extends {BaseAPI}
*/
export class DefaultApi extends BaseAPI {
/**
*
* @summary Deploys the bytecode of a Solidity contract without the need of keychain
* @param {DeployContractSolidityBytecodeNoKeychainV1Request} [deployContractSolidityBytecodeNoKeychainV1Request]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof DefaultApi
*/
public deployContractSolBytecodeNoKeychainV1(deployContractSolidityBytecodeNoKeychainV1Request?: DeployContractSolidityBytecodeNoKeychainV1Request, options?: AxiosRequestConfig) {
return DefaultApiFp(this.configuration).deployContractSolBytecodeNoKeychainV1(deployContractSolidityBytecodeNoKeychainV1Request, options).then((request) => request(this.axios, this.basePath));
}

/**
*
* @summary Deploys the bytecode of a Solidity contract.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import Web3JsQuorum, { IWeb3Quorum } from "web3js-quorum";
import { Contract, ContractSendMethod } from "web3-eth-contract";
import { TransactionReceipt } from "web3-eth";
import {
DeployContractSolidityBytecodeNoKeychainV1Request,
GetBalanceV1Request,
GetBalanceV1Response,
Web3TransactionReceipt,
Expand Down Expand Up @@ -100,6 +101,7 @@ import {
GetOpenApiSpecV1Endpoint,
IGetOpenApiSpecV1EndpointOptions,
} from "./web-services/get-open-api-spec-v1-endpoint";
import { DeployContractSolidityBytecodeNoKeychainEndpoint } from "./web-services/deploy-contract-solidity-bytecode-no-keychain-endpoint";

export const E_KEYCHAIN_NOT_FOUND = "cactus.connector.besu.keychain_not_found";

Expand Down Expand Up @@ -230,6 +232,13 @@ export class PluginLedgerConnectorBesu
});
endpoints.push(endpoint);
}
{
const endpoint = new DeployContractSolidityBytecodeNoKeychainEndpoint({
connector: this,
logLevel: this.options.logLevel,
});
endpoints.push(endpoint);
}
{
const endpoint = new GetBalanceEndpoint({
connector: this,
Expand Down Expand Up @@ -912,6 +921,83 @@ export class PluginLedgerConnectorBesu
return deployResponse;
}

public async deployContractNoKeychain(
req: DeployContractSolidityBytecodeNoKeychainV1Request,
): Promise<DeployContractSolidityBytecodeV1Response> {
const fnTag = `${this.className}#deployContract()`;
Checks.truthy(req, `${fnTag} req`);
if (isWeb3SigningCredentialNone(req.web3SigningCredential)) {
throw new Error(`${fnTag} Cannot deploy contract with pre-signed TX`);
}
const { contractName, contractJSONString } = req;
const networkId = await this.web3.eth.net.getId();

const tmpContract = new this.web3.eth.Contract(req.contractAbi);
const deployment = tmpContract.deploy({
data: req.bytecode,
arguments: req.constructorArgs,
});

const abi = deployment.encodeABI();
const data = abi.startsWith("0x") ? abi : `0x${abi}`;
this.log.debug(`Deploying "${req.contractName}" with data %o`, data);

const web3SigningCredential = req.web3SigningCredential as
| Web3SigningCredentialPrivateKeyHex
| Web3SigningCredentialCactusKeychainRef;

const runTxResponse = await this.transact({
transactionConfig: {
data,
from: web3SigningCredential.ethAccount,
gas: req.gas,
gasPrice: req.gasPrice,
},
consistencyStrategy: {
blockConfirmations: 0,
receiptType: ReceiptType.NodeTxPoolAck,
timeoutMs: req.timeoutMs || 60000,
},
web3SigningCredential,
privateTransactionConfig: req.privateTransactionConfig,
});

const { transactionReceipt: receipt } = runTxResponse;
const { status, contractAddress } = receipt;

Checks.truthy(status, `${this.className}#deployContract():status`);

Checks.truthy(
contractAddress,
`${this.className}#deployContract():contractAddress`,
);

if (contractJSONString) {
const networkInfo = { address: contractAddress };
const contractJSON = JSON.parse(contractJSONString);
this.log.debug("Contract JSON: \n%o", JSON.stringify(contractJSON));
const contract = new this.web3.eth.Contract(
contractJSON.abi,
contractAddress || " ",
);
this.contracts[contractName] = contract;
const network = { [networkId]: networkInfo };
contractJSON.networks = network;
} else {
const errorMessage =
`${fnTag} Cannot create an instance of the contract instance because` +
`the contractName in the request does not exist on the keychain`;
throw new createHttpError[400](errorMessage);
}

// creating solidity byte code response
const deployResponse: DeployContractSolidityBytecodeV1Response = {
transactionReceipt: runTxResponse.transactionReceipt,
};

return deployResponse;
}

public async signTransaction(
req: SignTransactionRequest,
): Promise<Optional<SignTransactionResponse>> {
Expand Down
Loading

0 comments on commit 1319363

Please sign in to comment.