Skip to content

Wip/testnet manager #489

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
acbd49b
wip: add shutdown and kicking of random peer
May 21, 2024
12a7750
Merge branch 'staging/v6' of github.com:LIT-Protocol/js-sdk into wip/…
May 22, 2024
f0e8139
Merge branch 'staging/v6' of github.com:LIT-Protocol/js-sdk into wip/…
May 24, 2024
9235f1b
Merge branch 'staging/v6' of github.com:LIT-Protocol/js-sdk into wip/…
May 25, 2024
1102cbb
Merge branch 'fix/tinny-testnet-minting' of github.com:LIT-Protocol/j…
May 25, 2024
35b31e7
log resp from validator kick
May 26, 2024
643ef96
wip add more api support for testnet manager api endpoints
May 28, 2024
3bd5c85
ref(tinny): fix method name
May 29, 2024
c0d40c8
ref(tinny): env changes for tinny enviorment flags
May 31, 2024
56d62dd
Merge branch 'staging/v6' of github.com:LIT-Protocol/js-sdk into wip/…
May 31, 2024
b86a24a
chore: update readme with shiva flags
May 31, 2024
02a8509
ref(tinny): remove test
May 31, 2024
b8261d7
ref(tinny): fixes from testing and feedback for shiva usage with tinny
May 31, 2024
6a34e9c
ref(tinny): tweaks to shiva env variables
Jun 1, 2024
d0bc56f
feat(tinny): move shiva bindings to their own files
Jun 3, 2024
73dc7b5
Merge branch 'master' into wip/testnet-manager
Jun 5, 2024
9d126d8
Merge branch 'master' of github.com:LIT-Protocol/js-sdk into wip/test…
Jun 5, 2024
c143d98
ref(tinny): rename client file name
Jun 5, 2024
93dd0f6
Merge branch 'wip/testnet-manager' of github.com:LIT-Protocol/js-sdk …
Jun 5, 2024
f056693
dev(tinny): add more context to processEnv interface porperties for b…
Jun 5, 2024
5e2136b
ref(tinny): fix casing
Jun 5, 2024
c2ca194
ref(tinny): Fix import
Jun 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions local-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ Below is the API documentation for the `ProcessEnvs` interface, detailing the co
| `RUN_IN_BAND_INTERVAL` | The interval in milliseconds to run the tests in a single thread. |
| `LIT_RPC_URL` | The URL of the Lit RPC server. If running locally on Anvil, it should be 'http://127.0.0.1:8545'. |
| `LIT_OFFICIAL_RPC` | The URL of the official Lit RPC server, usually 'https://chain-rpc.litprotocol.com/http' but can be changed if needed. |
| `SHIVA_URL` | URl to connect to Shiva (our testing tool for network management). |
| `LIT_NODE_BINARY_PATH` | URl to connect to Shiva (our testing tool for network management). |
| `USE_LIT_NODE_BINARY` | Flag to indicate if a binary path should be used for testnet spawning or if it should be built from source. |
| `STOP_TESTNET` | Flag to stop a single running testnet after the test run concludes. |

# Writing a test

Expand Down
240 changes: 240 additions & 0 deletions local-tests/setup/shiva-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
export interface ShivaEnvs {
/**
* If runnnig no localchain this flag will stop the running testnet when the test
* run has finished. Which is when all pending task promises have settled.
*/
STOP_TESTNET: boolean;

/**
* URL for Testnet manager intigration
*/
TESTNET_MANAGER_URL: string;

/**
* Path to the Lit Node Binary to use. Can be configured through an env variable
* LIT_NODE_BINARY_PATH where the value is the local path to a built Lit Action Binary
* If flagging to not use the binary path this option will be ignored.
* See {@link USE_LIT_BINARIES} and {@link LIT_ACTION_BINARY_PATH}
*/
LIT_NODE_BINARY_PATH: string;

/**
* Path to lit action binary to use, Can be defined through env variable
* LIT_ACTION_BINARY_PATH where the value is the local path to a built Lit Action Binary.
* If flagging not to use the binary path this option will be ignored
* See {@link USE_LIT_BINARIES} and {@link LIT_NODE_BINARY_PATH}
*/
LIT_ACTION_BINARY_PATH: string;

/**
* Flag to indicate if the provided binary path should be used
* or if the testnet should be built from source before starting.
*/
USE_LIT_BINARIES: boolean;
}

export class TestnetClient {
private _id: string;
private _info: any;
private _processEnvs: ShivaEnvs;
private _currentState: string;

constructor(id: string, envs: ShivaEnvs) {
this._processEnvs = envs;
this._id = id;
}

/**
* Polls a given testnet for the ACTIVE state
* polls on a 500 milisecond interval
*/
public async pollTestnetForActive() {
let state = 'Busy';
while (state != 'Active') {
const pollRes = await fetch(
this._processEnvs.TESTNET_MANAGER_URL + '/test/poll/testnet/' + this._id
);
const res = await pollRes.json();
state = res.body;
console.log('found state to be', res);
if (state != 'Active') {
await new Promise<void>((res, _) => {
setTimeout(() => {
res();
}, 500);
});
}
}
}

/**
* returns the config for a given testnet
* struct reference for config
* pub struct TestNetInfo {
pub contract_addresses: ContractAddresses,
pub validator_addresses: Vec<String>,
pub epoch_length: i32,
}
*/
public getTestnetConfig() {
return fetch(
this._processEnvs.TESTNET_MANAGER_URL +
'/test/get/info/testnet/' +
this._id
)
.then((res: Response) => {
return res.json();
})
.then((info: any) => {
this._info = info.body;
this._currentState = info.lastStateObserved;
console.log('setting testnet info: ', this._info);
});
}

/**
* Will wait for the NEXT epoch and return a resposne when the epoch has fully transitioned.
* The return time is directly proportional to the epoch transition time config and where the network is with the current epoch.
*/
public transitionEpochAndWait() {
return fetch(
this._processEnvs.TESTNET_MANAGER_URL +
'/test/action/transition/epoch/wait/' +
this._id
)
.then((res: Response) => {
if (res.status === 200) {
return res.json();
}
})
.then((body: any) => {
console.log('Stopped random peer: ', body);
});
}

/**
* Stops a random peer and waits for the next epoc to transiton.
* The return time is directly proportional to the epoch transition time config and where the network is with the current epoch.
*/
public stopRandomNetworkPeerAndWaitForNextEpoch() {
return fetch(
this._processEnvs.TESTNET_MANAGER_URL +
'/test/action/stop/random/wait/' +
this._id
)
.then((res: Response) => {
if (res.status === 200) {
return res.json();
}
})
.then((body: any) => {
console.log('validator kick response: ', body);
});
}

/*
Stops the testnet
*/
public stopTestnet() {
console.log('stopping testnet with id:', this._id);
return fetch(
this._processEnvs.TESTNET_MANAGER_URL + '/test/delete/testnet/' + this._id
)
.then((res: Response) => {
return res.json();
})
.then((body: any) => {
console.log('shutdown respone: ', body);
});
}
}

export class ShivaClient {
private _clients: Map<string, TestnetClient>;
public processEnvs: ShivaEnvs = {
STOP_TESTNET: process.env[`STOP_TESTNET`] === 'true',
TESTNET_MANAGER_URL:
process.env['TESTNET_MANAGER_URL'] || 'http://0.0.0.0:8000',
USE_LIT_BINARIES: process.env[`USE_LIT_BINARIES`] === `true`,
LIT_NODE_BINARY_PATH:
process.env['LIT_NODE_BINARY_PATH'] ||
`./../../../lit-assets/rust/lit-node/target/debug/lit_node`,
LIT_ACTION_BINARY_PATH:
process.env['LIT_ACTION_BINARY_PATH'] ||
`./../../../lit-assets/rust/lit-actions/target/debug/lit_actions`,
};

constructor() {
this._clients = new Map();
}

/**
* Used to start an instance of a lit network through the Lit Testnet Manager
* if an isntance exists, we will just take it as we optimistically assume it will not be shut down in the test life time.
* If an instance does not exist then we create one
* struct reference
pub struct TestNetCreateRequest {
pub node_count: usize,
pub polling_interval: String,
pub epoch_length: i32,
pub custom_build_path: Option<String>,
pub lit_action_server_custom_build_path: Option<String>,
pub existing_config_path: Option<String>,
pub which: Option<String>,
pub ecdsa_round_timeout: Option<String>,
pub enable_rate_limiting: Option<String>,
}
*/
async startTestnetManager(): Promise<TestnetClient> {
const existingTestnetResp = await fetch(
this.processEnvs.TESTNET_MANAGER_URL + '/test/get/testnets'
);
const existingTestnets: string[] = await existingTestnetResp.json();
if (existingTestnets.length > 0) {
this._clients.set(
existingTestnets[0],
new TestnetClient(existingTestnets[0], this.processEnvs)
);
return this._clients.get(existingTestnets[0]);
} else {
console.log(
'lit node binary path: ',
this.processEnvs.LIT_NODE_BINARY_PATH
);
console.log(
'lit action server binary path: ',
this.processEnvs.LIT_ACTION_BINARY_PATH
);
let body: Record<string, any> = {
nodeCount: 6,
pollingInterval: '2000',
epochLength: 100,
};

if (this.processEnvs.USE_LIT_BINARIES) {
body.customBuildPath = this.processEnvs.LIT_NODE_BINARY_PATH;
body.litActionServerCustomBuildPath =
this.processEnvs.LIT_ACTION_BINARY_PATH;
}
console.log('Testnet create args: ', body);
const createTestnetResp = await fetch(
this.processEnvs.TESTNET_MANAGER_URL + '/test/create/testnet',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
}
);

const createTestnet = await createTestnetResp.json();
this._clients.set(
createTestnet.testnetId,
new TestnetClient(createTestnet.testnetId, this.processEnvs)
);

return this._clients.get(createTestnet.testnetId);
}
}
}
31 changes: 29 additions & 2 deletions local-tests/setup/tinny-environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { TinnyPerson } from './tinny-person';
import networkContext from './networkContext.json';
import { ethers } from 'ethers';
import { createSiweMessage, generateAuthSig } from '@lit-protocol/auth-helpers';
import { ShivaClient, TestnetClient } from './shiva-client';

export class TinnyEnvironment {
public network: LIT_TESTNET;
Expand All @@ -36,7 +37,7 @@ export class TinnyEnvironment {
process.env['LIT_OFFICIAL_RPC'] ||
'https://chain-rpc.litprotocol.com/http',
TIME_TO_RELEASE_KEY: parseInt(process.env['TIME_TO_RELEASE_KEY']) || 10000,
RUN_IN_BAND: Boolean(process.env['RUN_IN_BAND']) || false,
RUN_IN_BAND: process.env['RUN_IN_BAND'] === 'false',
RUN_IN_BAND_INTERVAL: parseInt(process.env['RUN_IN_BAND_INTERVAL']) || 5000,

// Available Accounts
Expand All @@ -63,7 +64,7 @@ export class TinnyEnvironment {
'0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6',
],
KEY_IN_USE: new Array(),
NO_SETUP: Boolean(process.env['NO_SETUP']) || false,
NO_SETUP: process.env['NO_SETUP'] === 'false',
};

public litNodeClient: LitNodeClient;
Expand All @@ -87,6 +88,9 @@ export class TinnyEnvironment {
address: 'cosmos14wp2s5kv07lt220rzfae57k73yv9z2azrmulku',
};

//=========== PRIVATE MEMBERS ===========
private _shivaClient: ShivaClient = new ShivaClient();
private _testnet: TestnetClient | undefined;
constructor(network?: LIT_TESTNET) {
// -- setup networkj
this.network = network || this.processEnvs.NETWORK;
Expand Down Expand Up @@ -311,6 +315,13 @@ export class TinnyEnvironment {
console.log('[𐬺🧪 Tinny Environment𐬺] Skipping setup');
return;
}
if (this.network === LIT_TESTNET.LOCALCHAIN) {
this._testnet = await this._shivaClient.startTestnetManager();
// wait for the testnet to be active before we start the tests.
await this._testnet.pollTestnetForActive();
await this._testnet.getTestnetConfig();
}

await this.setupLitNodeClient();
await this.setupSuperCapacityDelegationAuthSig();
await this.setupBareEthAuthSig();
Expand All @@ -337,6 +348,22 @@ export class TinnyEnvironment {
});
}

//============= SHIVA ENDPOINTS =============
/**
* Will stop the testnet that is being used in the test run.
*/
async stopTestnet() {
if (
this.network === LIT_TESTNET.LOCALCHAIN &&
this._shivaClient.processEnvs.STOP_TESTNET
) {
await this._testnet.stopTestnet();
} else {
console.log('skipping testnet shutdown.');
}
}
//============= END SHIVA ENDPOINTS =============

/**
* Context: the reason this is created instead of individually is because we can't allocate capacity beyond the global
* max capacity.
Expand Down
12 changes: 6 additions & 6 deletions local-tests/setup/tinny-operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const runInBand = async ({
}: {
tests: any;
devEnv: TinnyEnvironment;
}): Promise<void> => {
}): Promise<number> => {
const filters = getFiltersFlag();
const testsToRun = Object.entries(tests).filter(
([testName]) => filters.length === 0 || filters.includes(testName)
Expand Down Expand Up @@ -108,9 +108,9 @@ export const runInBand = async ({
);

if (failedTests.length > 0) {
process.exit(1); // Exit with error code if any test failed
return 1; // Exit with error code if any test failed
} else {
process.exit(0); // Exit successfully if all tests passed
return 0; // Exit successfully if all tests passed
}
};

Expand All @@ -127,7 +127,7 @@ export const runTestsParallel = async ({
}: {
tests: any;
devEnv: TinnyEnvironment;
}): Promise<void> => {
}): Promise<number> => {
const filters = getFiltersFlag();
const excludeFilters = getExcludeFlags();

Expand Down Expand Up @@ -224,8 +224,8 @@ export const runTestsParallel = async ({
}

if (failedTests.length > 0) {
process.exit(1); // Exit with error code if any test failed
return 1; // Exit with error code if any test failed
} else {
process.exit(0); // Exit successfully if all tests passed
return 0; // Exit successfully if all tests passed
}
};
8 changes: 5 additions & 3 deletions local-tests/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,12 @@ import { testExecuteJsBroadcastAndCollect } from './tests/testExecuteJsBroadcast
},
devEnv,
};

let res;
if (devEnv.processEnvs.RUN_IN_BAND) {
await runInBand(testConfig);
res = await runInBand(testConfig);
} else {
await runTestsParallel(testConfig);
res = await runTestsParallel(testConfig);
}
await devEnv.stopTestnet();
process.exit(res);
})();
Loading