Skip to content

Commit

Permalink
Merge pull request #813 from starknet-io/next-version
Browse files Browse the repository at this point in the history
Next version
  • Loading branch information
tabaktoni authored Nov 10, 2023
2 parents e94ed10 + 07aaa17 commit e377664
Show file tree
Hide file tree
Showing 28 changed files with 10,948 additions and 7,313 deletions.
83 changes: 16 additions & 67 deletions __tests__/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import fs from 'node:fs';
import path from 'node:path';

import { Account, ProviderInterface, RpcProvider, SequencerProvider, json } from '../src';
import { BaseUrl } from '../src/constants';
import {
CairoVersion,
CompiledSierra,
CompiledSierraCasm,
LegacyCompiledContract,
Expand Down Expand Up @@ -48,37 +46,12 @@ export const compiledC1v2Casm = readContractSierraCasm('cairo/helloCairo2/compil
export const compiledC210 = readContractSierra('cairo/cairo210/cairo210.sierra');
export const compiledC210Casm = readContractSierraCasm('cairo/cairo210/cairo210');

/* Default test config based on run `starknet-devnet --seed 0` */
const DEFAULT_TEST_PROVIDER_URL = 'http://127.0.0.1:5050/';

/* User defined config or default one */
const BASE_URL = process.env.TEST_PROVIDER_BASE_URL || DEFAULT_TEST_PROVIDER_URL;
const RPC_URL = process.env.TEST_RPC_URL;

/* Detect user defined node or sequencer, if none default to sequencer if both default to node */
const PROVIDER_URL = RPC_URL || BASE_URL;

/** explicit is local devnet (undefined,'','1','true','TRUE') = true else false */
const LOCAL_DEVNET = ['1', 'TRUE', ''].includes((process.env.LOCAL_DEVNET || '').toUpperCase());

/* Detect is localhost devnet, it can be also localhost RPC node */
export const IS_LOCALHOST_DEVNET =
LOCAL_DEVNET && (PROVIDER_URL.includes('localhost') || PROVIDER_URL.includes('127.0.0.1'));

export const IS_DEVNET_RPC = IS_LOCALHOST_DEVNET && PROVIDER_URL.includes('rpc');
export const IS_DEVNET_SEQUENCER = IS_LOCALHOST_DEVNET && !PROVIDER_URL.includes('rpc');

/* Definitions */
export const IS_RPC = !!RPC_URL;
export const IS_SEQUENCER = !RPC_URL;
export const IS_SEQUENCER_GOERLI = PROVIDER_URL.includes(BaseUrl.SN_GOERLI);

export const getTestProvider = (): ProviderInterface => {
const provider = RPC_URL
? new RpcProvider({ nodeUrl: RPC_URL })
: new SequencerProvider({ baseUrl: BASE_URL });
const provider = process.env.TEST_RPC_URL
? new RpcProvider({ nodeUrl: process.env.TEST_RPC_URL })
: new SequencerProvider({ baseUrl: process.env.TEST_PROVIDER_BASE_URL || '' });

if (IS_LOCALHOST_DEVNET) {
if (process.env.IS_LOCALHOST_DEVNET === 'true') {
// accelerate the tests when running locally
const originalWaitForTransaction = provider.waitForTransaction.bind(provider);
provider.waitForTransaction = (
Expand All @@ -92,46 +65,22 @@ export const getTestProvider = (): ProviderInterface => {
return provider;
};

// test account with fee token balance
export const getTestAccount = (provider: ProviderInterface) => {
let testAccountAddress = process.env.TEST_ACCOUNT_ADDRESS;
let testAccountPrivateKey = process.env.TEST_ACCOUNT_PRIVATE_KEY;

if (!IS_LOCALHOST_DEVNET) {
if (!testAccountPrivateKey) {
throw new Error('TEST_ACCOUNT_PRIVATE_KEY is not set');
}
if (!testAccountAddress) {
throw new Error('TEST_ACCOUNT_ADDRESS is not set');
}
} else if (!testAccountAddress || !testAccountPrivateKey) {
// use defaults for devnet only if they are not set

// TODO: refactor to retrieve from devnet's /predeployed_accounts endpoint
[testAccountAddress, testAccountPrivateKey] = IS_RPC
? [
'0x64b48806902a367c8598f4f95c305e8c1a1acba5f082d294a43793113115691',
'0x71d7bb07b9a64f6f78ac4c816aff4da9',
]
: [
'0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a',
'0xe3e70682c2094cac629f6fbed82c07cd',
];
}
const cairoVersion = (process.env.ACCOUNT_CAIRO_VERSION as CairoVersion) || '0';

return new Account(provider, toHex(testAccountAddress), testAccountPrivateKey, cairoVersion);
return new Account(
provider,
toHex(process.env.TEST_ACCOUNT_ADDRESS || ''),
process.env.TEST_ACCOUNT_PRIVATE_KEY || ''
);
};

const describeIf = (condition: boolean) => (condition ? describe : describe.skip);
export const describeIfSequencer = describeIf(IS_SEQUENCER);
export const describeIfRpc = describeIf(IS_RPC);
export const describeIfNotRpc = describeIf(!IS_RPC);
export const describeIfNotDevnet = describeIf(!IS_LOCALHOST_DEVNET);
export const describeIfDevnet = describeIf(IS_LOCALHOST_DEVNET);
export const describeIfDevnetRpc = describeIf(IS_DEVNET_RPC);
export const describeIfDevnetSequencer = describeIf(IS_DEVNET_SEQUENCER);
export const describeIfSequencerGoerli = describeIf(IS_SEQUENCER_GOERLI);
export const describeIfSequencer = describeIf(process.env.IS_SEQUENCER === 'true');
export const describeIfRpc = describeIf(process.env.IS_RPC === 'true');
export const describeIfNotDevnet = describeIf(process.env.IS_LOCALHOST_DEVNET === 'false');
export const describeIfDevnet = describeIf(process.env.IS_LOCALHOST_DEVNET === 'true');
export const describeIfDevnetRpc = describeIf(process.env.IS_RPC_DEVNET === 'true');
export const describeIfDevnetSequencer = describeIf(process.env.IS_SEQUENCER_DEVNET === 'true');
export const describeIfSequencerGoerli = describeIf(process.env.IS_SEQUENCER_GOERLI === 'true');

export const erc20ClassHash = '0x54328a1075b8820eb43caf0caa233923148c983742402dcfc38541dd843d01a';
export const wrongClassHash = '0x000000000000000000000000000000000000000000000000000000000000000';
6 changes: 6 additions & 0 deletions __tests__/jest.setup.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* Test Setup
* Run before each test
* ref: order of execution jestGlobalSetup.ts -> jest.setup.ts -> fixtures.ts
*/

import 'isomorphic-fetch';

/* eslint-disable no-console */
Expand Down
245 changes: 245 additions & 0 deletions __tests__/jestGlobalSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
/* eslint-disable no-console */
/**
* Asynchronous Global Test Setup
* Run only once
* ref: order of execution jestGlobalSetup.ts -> jest.setup.ts -> fixtures.ts
*/

import { getDefaultNodeUrl } from '../src';
import { BaseUrl } from '../src/constants';

type DevnetStrategy = {
isDevnet: boolean;
isRS: boolean;
};
type ProviderType = {
sequencer: boolean;
rpc: boolean;
};

/**
* Global Setup Fixtures
*/

/* Default test config based on run `starknet-devnet --seed 0` */
const GS_DEFAULT_TEST_PROVIDER_URL = 'http://127.0.0.1:5050/';

const setIfNullish = (envName: string, setValue?: string | boolean) => {
process.env[envName] ??= setValue?.toString();
};

const localDevnetDetectionStrategy = async () => {
const setup = (strategy: DevnetStrategy) => {
setIfNullish('IS_LOCALHOST_DEVNET', strategy.isDevnet ? 'true' : 'false');
setIfNullish(
'IS_RPC_DEVNET',
strategy.isDevnet && (strategy.isRS || process.env.TEST_RPC_URL) ? 'true' : 'false'
);
setIfNullish(
'IS_SEQUENCER_DEVNET',
strategy.isDevnet && process.env.IS_RPC_DEVNET === 'false' ? 'true' : 'false'
);
return strategy;
};

const strategy: DevnetStrategy = {
isDevnet: false,
isRS: false,
};

// if is_alive work it is local devnet
const devnetResult = await fetch(`${GS_DEFAULT_TEST_PROVIDER_URL}is_alive`)
.then((res) => res.text())
.catch(() => '');
if (devnetResult !== 'Alive!!!') {
return setup(strategy);
}
strategy.isDevnet = true;

// if on base url RPC endpoint work it is devnet-rs else it devnet-py
try {
const response = await fetch(`${GS_DEFAULT_TEST_PROVIDER_URL}`, {
method: 'POST',
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'starknet_syncing' }),
});
const json = await response.json();
strategy.isRS = json.jsonrpc === '2.0';
} catch (error) {
return setup(strategy);
}

return setup(strategy);
};

const sequencerOrRpc = async (devnetStrategy?: DevnetStrategy) => {
const setup = (providerType: ProviderType) => {
setIfNullish('IS_SEQUENCER', providerType.sequencer ? 'true' : 'false');
setIfNullish('IS_RPC', providerType.rpc ? 'true' : 'false');
setIfNullish(
'IS_SEQUENCER_GOERLI',
(process.env.TEST_PROVIDER_BASE_URL || process.env.TEST_RPC_URL || '').includes(
BaseUrl.SN_GOERLI
)
? 'true'
: 'false'
);
return providerType;
};
let result: ProviderType = { sequencer: false, rpc: false };
if (process.env.TEST_PROVIDER_BASE_URL) {
return setup({ ...result, sequencer: true });
}
if (process.env.TEST_RPC_URL) {
return setup({ ...result, rpc: true });
}
// nor sequencer nor rpc provided, try with local devnet strategy
if (devnetStrategy && devnetStrategy.isDevnet) {
result = { sequencer: !devnetStrategy.isRS, rpc: devnetStrategy.isRS };
if (result.sequencer) {
process.env.TEST_PROVIDER_BASE_URL = GS_DEFAULT_TEST_PROVIDER_URL;
} else if (result.rpc) {
process.env.TEST_RPC_URL = GS_DEFAULT_TEST_PROVIDER_URL;
}
}
return setup(result);
};

const setAccount = async (devnetStrategy: DevnetStrategy) => {
const fetchAccount = async (URL: string) => {
const response = await fetch(`${URL}predeployed_accounts`);
const accounts = await response.json();
process.env.TEST_ACCOUNT_ADDRESS = accounts[0].address;
process.env.TEST_ACCOUNT_PRIVATE_KEY = accounts[0].private_key;
process.env.INITIAL_BALANCE = accounts[0].initial_balance;
};

if (process.env.TEST_ACCOUNT_ADDRESS && process.env.TEST_ACCOUNT_PRIVATE_KEY) {
return true;
}
if (process.env.TEST_ACCOUNT_ADDRESS || process.env.TEST_ACCOUNT_PRIVATE_KEY) {
throw new Error(
'If you are providing one of you need to provide both: TEST_ACCOUNT_ADDRESS & TEST_ACCOUNT_PRIVATE_KEY'
);
}
const providedURL = process.env.TEST_PROVIDER_BASE_URL || process.env.TEST_RPC_URL;
if (devnetStrategy.isDevnet) {
// get account from devnet
try {
await fetchAccount(GS_DEFAULT_TEST_PROVIDER_URL);
return true;
} catch (error) {
console.error('Fetching account from devnet failed');
}
} else if (providedURL) {
// try to get it from remote devnet
try {
await fetchAccount(providedURL);
return true;
} catch (error) {
console.error(`Fetching account from provided url ${providedURL} failed`);
}
}

throw new Error(
'Setting Account using all known strategies failed, provide basic test parameters'
);
};

const verifySetup = (final?: boolean) => {
const warnings: string[] = [];
if (!process.env.TEST_ACCOUNT_ADDRESS) {
if (final) throw new Error('TEST_ACCOUNT_ADDRESS env is not provided');
else warnings.push('TEST_ACCOUNT_ADDRESS env is not provided!');
}
if (!process.env.TEST_ACCOUNT_PRIVATE_KEY) {
if (final) throw new Error('TEST_ACCOUNT_PRIVATE_KEY env is not provided');
else warnings.push('TEST_ACCOUNT_PRIVATE_KEY env is not provided!');
}
if (!process.env.TEST_RPC_URL) {
process.env.TEST_RPC_URL = getDefaultNodeUrl();
console.warn('TEST_RPC_URL env is not provided');
}

if (warnings.length > 0) {
console.log('\x1b[33m', warnings.join('\n'), '\x1b[0m');
delete process.env.TEST_ACCOUNT_ADDRESS;
delete process.env.TEST_ACCOUNT_PRIVATE_KEY;
return false;
}

if (!final) {
setIfNullish('IS_LOCALHOST_DEVNET', 'false');
setIfNullish('IS_RPC_DEVNET', 'false');
setIfNullish('IS_SEQUENCER_DEVNET', 'false');
setIfNullish('IS_RPC', process.env.TEST_RPC_URL ? 'true' : 'false');
setIfNullish('IS_SEQUENCER', process.env.TEST_PROVIDER_BASE_URL ? 'true' : 'false');
setIfNullish(
'IS_SEQUENCER_GOERLI',
(process.env.TEST_PROVIDER_BASE_URL || process.env.TEST_RPC_URL || '').includes(
BaseUrl.SN_GOERLI
)
? 'true'
: 'false'
);
}

console.table({
TEST_ACCOUNT_ADDRESS: process.env.TEST_ACCOUNT_ADDRESS,
TEST_ACCOUNT_PRIVATE_KEY: '****',
INITIAL_BALANCE: process.env.INITIAL_BALANCE,
TEST_PROVIDER_BASE_URL: process.env.TEST_PROVIDER_BASE_URL,
TEST_RPC_URL: process.env.TEST_RPC_URL,
});

console.table({
IS_LOCALHOST_DEVNET: process.env.IS_LOCALHOST_DEVNET,
IS_RPC_DEVNET: process.env.IS_RPC_DEVNET,
IS_SEQUENCER_DEVNET: process.env.IS_SEQUENCER_DEVNET,
IS_RPC: process.env.IS_RPC,
IS_SEQUENCER: process.env.IS_SEQUENCER,
IS_SEQUENCER_GOERLI: process.env.IS_SEQUENCER_GOERLI,
});

console.log('Global Test Environment is Ready');
return true;
};

const executeStrategy = async () => {
// 1. Assume setup is provided and ready;
console.log('Global Test Setup Started');
if (verifySetup()) {
console.log('Using Provided Test Setup');
return true;
}

// 2. Try to detect devnet setup
console.log('Basic test parameters are missing, Auto Setup Started');
const devnetStrategy = await localDevnetDetectionStrategy();
if (devnetStrategy.isDevnet) {
if (devnetStrategy.isRS) {
console.log('Detected Devnet-RS');
} else {
console.log('Detected Devnet-PY');
}
}

const providerType = await sequencerOrRpc(devnetStrategy);
if (providerType.sequencer) {
console.log('Detected Sequencer');
} else if (providerType.rpc) {
console.log('Detected RPC');
}

const isAccountSet = await setAccount(devnetStrategy);
if (isAccountSet) {
console.log('Detected Account');
}

return verifySetup(true);
};

export default async (_globalConfig: any, _projectConfig: any) => {
const isSet = await executeStrategy();
if (!isSet) console.error('Test Setup Environment is NOT Ready');
};
Loading

0 comments on commit e377664

Please sign in to comment.