chore: replace jest with mocha
This commit is contained in:
committed by
Justin Starry
parent
612958ece0
commit
c675c67c26
@ -7,4 +7,4 @@
|
|||||||
/module.flow.js
|
/module.flow.js
|
||||||
/.eslintrc.js
|
/.eslintrc.js
|
||||||
/test/.eslintrc.js
|
/test/.eslintrc.js
|
||||||
/jest-environment.js
|
/test/dist
|
||||||
|
6
web3.js/.mocharc.js
Normal file
6
web3.js/.mocharc.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Configure Node.js tests
|
||||||
|
module.exports = {
|
||||||
|
require: ['@babel/register', 'esm'],
|
||||||
|
};
|
1
web3.js/.prettierignore
Normal file
1
web3.js/.prettierignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
test/dist
|
@ -15,3 +15,4 @@ npm run codecov
|
|||||||
make -C examples/bpf-c-noop/
|
make -C examples/bpf-c-noop/
|
||||||
cargo build-bpf --manifest-path examples/bpf-rust-noop/Cargo.toml
|
cargo build-bpf --manifest-path examples/bpf-rust-noop/Cargo.toml
|
||||||
npm run test:live-with-test-validator
|
npm run test:live-with-test-validator
|
||||||
|
npm run test:browser-with-test-validator
|
||||||
|
@ -24,7 +24,7 @@ eslint and flow-type are used.
|
|||||||
Helpful link: https://www.saltycrane.com/flow-type-cheat-sheet/latest/
|
Helpful link: https://www.saltycrane.com/flow-type-cheat-sheet/latest/
|
||||||
|
|
||||||
### Testing Framework
|
### Testing Framework
|
||||||
https://jestjs.io/
|
https://mochajs.org/
|
||||||
|
|
||||||
### API Documentation
|
### API Documentation
|
||||||
ESDoc is used to document the public API. See
|
ESDoc is used to document the public API. See
|
||||||
|
@ -5,11 +5,5 @@
|
|||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@babel/plugin-proposal-class-properties"
|
"@babel/plugin-proposal-class-properties"
|
||||||
],
|
]
|
||||||
"env": {
|
|
||||||
"test": {
|
|
||||||
"plugins": ["@babel/plugin-transform-runtime"],
|
|
||||||
"presets": ["@babel/preset-flow"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
1218
web3.js/flow-typed/npm/jest_v26.x.x.js
vendored
1218
web3.js/flow-typed/npm/jest_v26.x.x.js
vendored
File diff suppressed because it is too large
Load Diff
@ -1,27 +0,0 @@
|
|||||||
const NodeEnvironment = require('jest-environment-node');
|
|
||||||
|
|
||||||
class CustomEnvironment extends NodeEnvironment {
|
|
||||||
constructor(config, context) {
|
|
||||||
Object.assign(config.globals, {
|
|
||||||
Uint8Array,
|
|
||||||
ArrayBuffer,
|
|
||||||
});
|
|
||||||
super(config, context);
|
|
||||||
this.testPath = context.testPath;
|
|
||||||
this.docblockPragmas = context.docblockPragmas;
|
|
||||||
}
|
|
||||||
|
|
||||||
async setup() {
|
|
||||||
await super.setup();
|
|
||||||
}
|
|
||||||
|
|
||||||
async teardown() {
|
|
||||||
await super.teardown();
|
|
||||||
}
|
|
||||||
|
|
||||||
runScript(script) {
|
|
||||||
return super.runScript(script);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = CustomEnvironment;
|
|
@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"collectCoverage": true,
|
|
||||||
"collectCoverageFrom": ["src/**"],
|
|
||||||
"coverageReporters": ["json", "lcov", "text-summary", "html"]
|
|
||||||
}
|
|
21
web3.js/mocha.html
Normal file
21
web3.js/mocha.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Mocha Tests</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="stylesheet" href="./node_modules/mocha/mocha.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="mocha"></div>
|
||||||
|
<script src="./node_modules/mocha/mocha.js"></script>
|
||||||
|
<script class="mocha-init">
|
||||||
|
mocha.setup('bdd');
|
||||||
|
mocha.checkLeaks();
|
||||||
|
</script>
|
||||||
|
<script type="module" src="./test/dist/bundle.js"></script>
|
||||||
|
<script type="module" class="mocha-exec">
|
||||||
|
mocha.run();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -46,6 +46,7 @@
|
|||||||
"bpf-sdk:install": "npm run clean:fixtures; bin/bpf-sdk-install.sh .",
|
"bpf-sdk:install": "npm run clean:fixtures; bin/bpf-sdk-install.sh .",
|
||||||
"bpf-sdk:remove-symlinks": "find bpf-sdk -type l -print -exec cp {} {}.tmp \\; -exec mv {}.tmp {} \\;",
|
"bpf-sdk:remove-symlinks": "find bpf-sdk -type l -print -exec cp {} {}.tmp \\; -exec mv {}.tmp {} \\;",
|
||||||
"build": "cross-env NODE_ENV=production rollup -c",
|
"build": "cross-env NODE_ENV=production rollup -c",
|
||||||
|
"build:browser-test": "rollup -c test/rollup.config.js",
|
||||||
"build:fixtures": "set -ex; ./test/fixtures/noop-c/build.sh; ./test/fixtures/noop-rust/build.sh",
|
"build:fixtures": "set -ex; ./test/fixtures/noop-c/build.sh; ./test/fixtures/noop-rust/build.sh",
|
||||||
"clean:fixtures": "make -C examples/bpf-c-noop clean ",
|
"clean:fixtures": "make -C examples/bpf-c-noop clean ",
|
||||||
"clean": "rimraf ./coverage ./lib",
|
"clean": "rimraf ./coverage ./lib",
|
||||||
@ -70,14 +71,13 @@
|
|||||||
"pretty": "prettier --check '{,{examples,src,test}/**/}*.{j,t}s'",
|
"pretty": "prettier --check '{,{examples,src,test}/**/}*.{j,t}s'",
|
||||||
"pretty:fix": "prettier --write '{,{examples,src,test}/**/}*.{j,t}s'",
|
"pretty:fix": "prettier --write '{,{examples,src,test}/**/}*.{j,t}s'",
|
||||||
"re": "semantic-release --repository-url git@github.com:solana-labs/solana-web3.js.git",
|
"re": "semantic-release --repository-url git@github.com:solana-labs/solana-web3.js.git",
|
||||||
"test": "npm run build:fixtures && cross-env NODE_ENV=test jest --useStderr",
|
"test": "npm run build:fixtures && mocha './test/**/*.test.js'",
|
||||||
"test:cover": "npm run build:fixtures && cross-env NODE_ENV=test jest --coverage --useStderr",
|
"test:browser": "TEST_LIVE=1 npm run build:fixtures && npm run build:browser-test && mocha-headless-chrome -f http://localhost:8080/mocha.html --timeout 180000",
|
||||||
"test:live": "npm run build:fixtures && cross-env NODE_ENV=test TEST_LIVE=1 jest --useStderr",
|
"test:browser-with-server": "start-server-and-test 'http-server -p 8080' 8080 test:browser",
|
||||||
|
"test:browser-with-test-validator": "start-server-and-test 'solana-test-validator --reset --quiet' http://localhost:8899/health test:browser-with-server",
|
||||||
|
"test:live": "TEST_LIVE=1 npm run test",
|
||||||
"test:live-with-test-validator": "start-server-and-test 'solana-test-validator --reset --quiet' http://localhost:8899/health test:live",
|
"test:live-with-test-validator": "start-server-and-test 'solana-test-validator --reset --quiet' http://localhost:8899/health test:live",
|
||||||
"test:watch": "npm run build:fixtures && cross-env NODE_ENV=test jest --watch --useStderr"
|
"test:watch": "npm run build:fixtures && npm run test"
|
||||||
},
|
|
||||||
"jest": {
|
|
||||||
"testEnvironment": "./jest-environment"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.12.5",
|
"@babel/runtime": "^7.12.5",
|
||||||
@ -95,15 +95,19 @@
|
|||||||
"tweetnacl": "^1.0.0"
|
"tweetnacl": "^1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.12.13",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
||||||
"@babel/plugin-transform-runtime": "^7.12.10",
|
"@babel/plugin-transform-runtime": "^7.12.10",
|
||||||
"@babel/preset-env": "^7.12.11",
|
"@babel/preset-env": "^7.12.11",
|
||||||
"@babel/preset-flow": "^7.12.1",
|
"@babel/preset-flow": "^7.12.1",
|
||||||
|
"@babel/register": "^7.12.13",
|
||||||
"@commitlint/config-conventional": "^11.0.0",
|
"@commitlint/config-conventional": "^11.0.0",
|
||||||
"@commitlint/travis-cli": "^11.0.0",
|
"@commitlint/travis-cli": "^11.0.0",
|
||||||
|
"@rollup/plugin-alias": "^3.1.2",
|
||||||
"@rollup/plugin-babel": "^5.2.3",
|
"@rollup/plugin-babel": "^5.2.3",
|
||||||
"@rollup/plugin-commonjs": "^17.1.0",
|
"@rollup/plugin-commonjs": "^17.1.0",
|
||||||
"@rollup/plugin-json": "^4.1.0",
|
"@rollup/plugin-json": "^4.1.0",
|
||||||
|
"@rollup/plugin-multi-entry": "^4.0.0",
|
||||||
"@rollup/plugin-node-resolve": "^11.1.1",
|
"@rollup/plugin-node-resolve": "^11.1.1",
|
||||||
"@rollup/plugin-replace": "^2.3.4",
|
"@rollup/plugin-replace": "^2.3.4",
|
||||||
"@solana/spl-token": "^0.0.13",
|
"@solana/spl-token": "^0.0.13",
|
||||||
@ -111,6 +115,8 @@
|
|||||||
"@typescript-eslint/parser": "^4.14.2",
|
"@typescript-eslint/parser": "^4.14.2",
|
||||||
"acorn": "^8.0.1",
|
"acorn": "^8.0.1",
|
||||||
"babel-eslint": "^11.0.0-beta.2",
|
"babel-eslint": "^11.0.0-beta.2",
|
||||||
|
"chai": "^4.3.0",
|
||||||
|
"chai-as-promised": "^7.1.1",
|
||||||
"codecov": "^3.0.4",
|
"codecov": "^3.0.4",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"elfy": "^1.0.0",
|
"elfy": "^1.0.0",
|
||||||
@ -121,22 +127,21 @@
|
|||||||
"esdoc-importpath-plugin": "^1.0.2",
|
"esdoc-importpath-plugin": "^1.0.2",
|
||||||
"esdoc-inject-style-plugin": "^1.0.0",
|
"esdoc-inject-style-plugin": "^1.0.0",
|
||||||
"esdoc-standard-plugin": "^1.0.0",
|
"esdoc-standard-plugin": "^1.0.0",
|
||||||
<<<<<<< HEAD
|
|
||||||
"eslint": "7.19.0",
|
|
||||||
=======
|
|
||||||
"eslint": "^7.19.0",
|
"eslint": "^7.19.0",
|
||||||
>>>>>>> 37215dbc2... feat: add support for browser es modules
|
|
||||||
"eslint-config-prettier": "^7.0.0",
|
"eslint-config-prettier": "^7.0.0",
|
||||||
"eslint-plugin-flowtype": "^5.2.0",
|
"eslint-plugin-flowtype": "^5.2.0",
|
||||||
"eslint-plugin-import": "2.22.1",
|
"eslint-plugin-import": "2.22.1",
|
||||||
"eslint-plugin-jest": "22.19.0",
|
|
||||||
"eslint-plugin-prettier": "^3.0.0",
|
"eslint-plugin-prettier": "^3.0.0",
|
||||||
|
"esm": "^3.2.25",
|
||||||
"flow-bin": "0.130.0",
|
"flow-bin": "0.130.0",
|
||||||
"flow-remove-types": "^2.143.1",
|
"flow-remove-types": "^2.143.1",
|
||||||
"flow-typed": "3.2.1",
|
"flow-typed": "3.2.1",
|
||||||
"fs-file-tree": "1.1.1",
|
"fs-file-tree": "1.1.1",
|
||||||
"jest": "26.6.3",
|
"http-server": "^0.12.3",
|
||||||
"marked": "^1.1.0",
|
"marked": "^1.1.0",
|
||||||
|
"mocha": "^8.2.1",
|
||||||
|
"mocha-headless-chrome": "^3.1.0",
|
||||||
|
"mockttp": "^1.1.0",
|
||||||
"mz": "^2.7.0",
|
"mz": "^2.7.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "^2.0.0",
|
"prettier": "^2.0.0",
|
||||||
@ -146,8 +151,11 @@
|
|||||||
"rollup-plugin-node-polyfills": "^0.2.1",
|
"rollup-plugin-node-polyfills": "^0.2.1",
|
||||||
"rollup-plugin-terser": "^7.0.2",
|
"rollup-plugin-terser": "^7.0.2",
|
||||||
"semantic-release": "^17.0.2",
|
"semantic-release": "^17.0.2",
|
||||||
"start-server-and-test": "^1.11.6",
|
"sinon": "^9.2.4",
|
||||||
|
"start-server-and-test": "^1.12.0",
|
||||||
"typescript": "^4.1.3",
|
"typescript": "^4.1.3",
|
||||||
"watch": "^1.0.2"
|
"watch": "^1.0.2",
|
||||||
|
"webpack": "^5.21.0",
|
||||||
|
"webpack-cli": "^4.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,11 @@ function generateConfig(configType, format) {
|
|||||||
plugins: [
|
plugins: [
|
||||||
flow(),
|
flow(),
|
||||||
commonjs(),
|
commonjs(),
|
||||||
nodeResolve({browser, preferBuiltins: !browser, dedupe: ['bn.js']}),
|
nodeResolve({
|
||||||
|
browser,
|
||||||
|
preferBuiltins: !browser,
|
||||||
|
dedupe: ['bn.js', 'buffer'],
|
||||||
|
}),
|
||||||
babel({
|
babel({
|
||||||
exclude: '**/node_modules/**',
|
exclude: '**/node_modules/**',
|
||||||
babelHelpers: bundle ? 'bundled' : 'runtime',
|
babelHelpers: bundle ? 'bundled' : 'runtime',
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
// eslint-disable-line import/no-commonjs
|
|
||||||
extends: ['plugin:jest/recommended', '../.eslintrc.js'],
|
|
||||||
};
|
|
1
web3.js/test/.gitignore
vendored
Normal file
1
web3.js/test/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
dist
|
@ -1,86 +0,0 @@
|
|||||||
// @flow
|
|
||||||
|
|
||||||
import fetch from 'node-fetch';
|
|
||||||
|
|
||||||
type RpcRequest = {
|
|
||||||
method: string,
|
|
||||||
params?: Array<any>,
|
|
||||||
};
|
|
||||||
|
|
||||||
type RpcResponseError = {
|
|
||||||
message: string,
|
|
||||||
};
|
|
||||||
type RpcResponseResult = any;
|
|
||||||
type RpcResponse = {
|
|
||||||
error: ?RpcResponseError,
|
|
||||||
result: ?RpcResponseResult,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const mockRpc: Array<[string, RpcRequest, RpcResponse]> = [];
|
|
||||||
|
|
||||||
// Define TEST_LIVE in the environment to test against the real full node
|
|
||||||
// identified by `url` instead of using the mock
|
|
||||||
export const mockRpcEnabled = !process.env.TEST_LIVE;
|
|
||||||
|
|
||||||
let mockNotice = true;
|
|
||||||
|
|
||||||
// Suppress lint: 'JestMockFn' is not defined
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
const mock: JestMockFn<any, any> = jest.fn((fetchUrl, fetchOptions) => {
|
|
||||||
if (!mockRpcEnabled) {
|
|
||||||
if (mockNotice) {
|
|
||||||
console.log(
|
|
||||||
`Note: node-fetch mock is disabled, testing live against ${fetchUrl}`,
|
|
||||||
);
|
|
||||||
mockNotice = false;
|
|
||||||
}
|
|
||||||
return fetch(fetchUrl, fetchOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(mockRpc.length).toBeGreaterThanOrEqual(1);
|
|
||||||
const [mockUrl, mockRequest, mockResponse] = mockRpc.shift();
|
|
||||||
|
|
||||||
expect(fetchUrl).toBe(mockUrl);
|
|
||||||
expect(fetchOptions).toMatchObject({
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(fetchOptions.body).toBeDefined();
|
|
||||||
|
|
||||||
const body = JSON.parse(fetchOptions.body);
|
|
||||||
expect(body).toMatchObject(
|
|
||||||
Object.assign(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
method: 'invalid',
|
|
||||||
},
|
|
||||||
mockRequest,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
const response = Object.assign(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
id: body.id,
|
|
||||||
error: {
|
|
||||||
message: 'invalid error message',
|
|
||||||
},
|
|
||||||
result: 'invalid response',
|
|
||||||
},
|
|
||||||
mockResponse,
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
ok: true,
|
|
||||||
status: 200,
|
|
||||||
statusText: 'OK',
|
|
||||||
text: () => {
|
|
||||||
return Promise.resolve(JSON.stringify(response));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export default mock;
|
|
@ -1,77 +0,0 @@
|
|||||||
// @flow
|
|
||||||
|
|
||||||
import {Client as LiveClient} from 'rpc-websockets';
|
|
||||||
import EventEmitter from 'events';
|
|
||||||
|
|
||||||
type RpcRequest = {
|
|
||||||
method: string,
|
|
||||||
params?: Array<any>,
|
|
||||||
};
|
|
||||||
|
|
||||||
type RpcResponse = {
|
|
||||||
context: {
|
|
||||||
slot: number,
|
|
||||||
},
|
|
||||||
value: any,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Define TEST_LIVE in the environment to test against the real full node
|
|
||||||
// identified by `url` instead of using the mock
|
|
||||||
export const mockRpcEnabled = !process.env.TEST_LIVE;
|
|
||||||
|
|
||||||
export const mockRpcSocket: Array<[RpcRequest, RpcResponse]> = [];
|
|
||||||
|
|
||||||
class MockClient extends EventEmitter {
|
|
||||||
mockOpen = false;
|
|
||||||
subscriptionCounter = 0;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
connect() {
|
|
||||||
if (!this.mockOpen) {
|
|
||||||
this.mockOpen = true;
|
|
||||||
this.emit('open');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
close() {
|
|
||||||
if (this.mockOpen) {
|
|
||||||
this.mockOpen = false;
|
|
||||||
this.emit('close');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
notify(): Promise<any> {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
on(event: string, callback: Function): this {
|
|
||||||
return super.on(event, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
call(method: string, params: Array<any>): Promise<Object> {
|
|
||||||
expect(mockRpcSocket.length).toBeGreaterThanOrEqual(1);
|
|
||||||
const [mockRequest, mockResponse] = mockRpcSocket.shift();
|
|
||||||
|
|
||||||
expect(method).toBe(mockRequest.method);
|
|
||||||
expect(params).toMatchObject(mockRequest.params);
|
|
||||||
|
|
||||||
let id = this.subscriptionCounter++;
|
|
||||||
const response = {
|
|
||||||
subscription: id,
|
|
||||||
result: mockResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
setImmediate(() => {
|
|
||||||
const eventName = method.replace('Subscribe', 'Notification');
|
|
||||||
this.emit(eventName, response);
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.resolve(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Client = mockRpcEnabled ? MockClient : LiveClient;
|
|
||||||
export {Client};
|
|
@ -1,12 +1,15 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import {Account} from '../src/account';
|
import {Account} from '../src/account';
|
||||||
|
import {expect} from 'chai';
|
||||||
|
import {Buffer} from 'buffer';
|
||||||
|
|
||||||
test('generate new account', () => {
|
describe('Account', () => {
|
||||||
|
it('generate new account', () => {
|
||||||
const account = new Account();
|
const account = new Account();
|
||||||
expect(account.secretKey).toHaveLength(64);
|
expect(account.secretKey).to.have.length(64);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('account from secret key', () => {
|
it('account from secret key', () => {
|
||||||
const secretKey = Buffer.from([
|
const secretKey = Buffer.from([
|
||||||
153,
|
153,
|
||||||
218,
|
218,
|
||||||
@ -74,7 +77,8 @@ test('account from secret key', () => {
|
|||||||
34,
|
34,
|
||||||
]);
|
]);
|
||||||
const account = new Account(secretKey);
|
const account = new Account(secretKey);
|
||||||
expect(account.publicKey.toBase58()).toBe(
|
expect(account.publicKey.toBase58()).to.eq(
|
||||||
'2q7pyhPwAwZ3QMfZrnAbDhnh9mDUqycszcpf86VgQxhF',
|
'2q7pyhPwAwZ3QMfZrnAbDhnh9mDUqycszcpf86VgQxhF',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
@ -1,40 +1,41 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import {AgentManager, DESTROY_TIMEOUT_MS} from '../src/agent-manager';
|
import {AgentManager, DESTROY_TIMEOUT_MS} from '../src/agent-manager';
|
||||||
|
import {expect} from 'chai';
|
||||||
import {sleep} from '../src/util/sleep';
|
import {sleep} from '../src/util/sleep';
|
||||||
|
|
||||||
jest.setTimeout(10 * 1000);
|
describe('AgentManager', () => {
|
||||||
|
it('works', async () => {
|
||||||
test('agent manager', async () => {
|
|
||||||
const manager = new AgentManager();
|
const manager = new AgentManager();
|
||||||
const agent = manager._agent;
|
const agent = manager._agent;
|
||||||
expect(manager._activeRequests).toBe(0);
|
expect(manager._activeRequests).to.eq(0);
|
||||||
expect(manager._destroyTimeout).toBeNull();
|
expect(manager._destroyTimeout).to.be.null;
|
||||||
|
|
||||||
manager.requestStart();
|
manager.requestStart();
|
||||||
|
|
||||||
expect(manager._activeRequests).toBe(1);
|
expect(manager._activeRequests).to.eq(1);
|
||||||
expect(manager._destroyTimeout).toBeNull();
|
expect(manager._destroyTimeout).to.be.null;
|
||||||
|
|
||||||
manager.requestEnd();
|
manager.requestEnd();
|
||||||
|
|
||||||
expect(manager._activeRequests).toBe(0);
|
expect(manager._activeRequests).to.eq(0);
|
||||||
expect(manager._destroyTimeout).not.toBeNull();
|
expect(manager._destroyTimeout).not.to.be.null;
|
||||||
|
|
||||||
manager.requestStart();
|
manager.requestStart();
|
||||||
manager.requestStart();
|
manager.requestStart();
|
||||||
|
|
||||||
expect(manager._activeRequests).toBe(2);
|
expect(manager._activeRequests).to.eq(2);
|
||||||
expect(manager._destroyTimeout).toBeNull();
|
expect(manager._destroyTimeout).to.be.null;
|
||||||
|
|
||||||
manager.requestEnd();
|
manager.requestEnd();
|
||||||
manager.requestEnd();
|
manager.requestEnd();
|
||||||
|
|
||||||
expect(manager._activeRequests).toBe(0);
|
expect(manager._activeRequests).to.eq(0);
|
||||||
expect(manager._destroyTimeout).not.toBeNull();
|
expect(manager._destroyTimeout).not.to.be.null;
|
||||||
expect(manager._agent).toBe(agent);
|
expect(manager._agent).to.eq(agent);
|
||||||
|
|
||||||
await sleep(DESTROY_TIMEOUT_MS);
|
await sleep(DESTROY_TIMEOUT_MS);
|
||||||
|
|
||||||
expect(manager._agent).not.toBe(agent);
|
expect(manager._agent).not.to.eq(agent);
|
||||||
|
}).timeout(2 * DESTROY_TIMEOUT_MS);
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import fs from 'mz/fs';
|
import fs from 'mz/fs';
|
||||||
|
import {expect, use} from 'chai';
|
||||||
|
import chaiAsPromised from 'chai-as-promised';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Connection,
|
Connection,
|
||||||
@ -9,22 +11,15 @@ import {
|
|||||||
sendAndConfirmTransaction,
|
sendAndConfirmTransaction,
|
||||||
Account,
|
Account,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
import {mockRpcEnabled} from './__mocks__/node-fetch';
|
|
||||||
import {url} from './url';
|
import {url} from './url';
|
||||||
import {newAccountWithLamports} from './new-account-with-lamports';
|
|
||||||
import {BPF_LOADER_PROGRAM_ID} from '../src/bpf-loader';
|
import {BPF_LOADER_PROGRAM_ID} from '../src/bpf-loader';
|
||||||
|
import {helpers} from './mocks/rpc-http';
|
||||||
|
|
||||||
if (!mockRpcEnabled) {
|
use(chaiAsPromised);
|
||||||
// The default of 5 seconds is too slow for live testing sometimes
|
|
||||||
jest.setTimeout(240000);
|
|
||||||
}
|
|
||||||
|
|
||||||
test('load BPF C program', async () => {
|
|
||||||
if (mockRpcEnabled) {
|
|
||||||
console.log('non-live test skipped');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (process.env.TEST_LIVE) {
|
||||||
|
describe('BPF Loader', () => {
|
||||||
|
it('load BPF C program', async () => {
|
||||||
const data = await fs.readFile('test/fixtures/noop-c/noop.so');
|
const data = await fs.readFile('test/fixtures/noop-c/noop.so');
|
||||||
|
|
||||||
const connection = new Connection(url, 'singleGossip');
|
const connection = new Connection(url, 'singleGossip');
|
||||||
@ -32,21 +27,32 @@ test('load BPF C program', async () => {
|
|||||||
const fees =
|
const fees =
|
||||||
feeCalculator.lamportsPerSignature *
|
feeCalculator.lamportsPerSignature *
|
||||||
BpfLoader.getMinNumSignatures(data.length);
|
BpfLoader.getMinNumSignatures(data.length);
|
||||||
const payerBalance = await connection.getMinimumBalanceForRentExemption(0);
|
const payerBalance = await connection.getMinimumBalanceForRentExemption(
|
||||||
|
0,
|
||||||
|
);
|
||||||
const executableBalance = await connection.getMinimumBalanceForRentExemption(
|
const executableBalance = await connection.getMinimumBalanceForRentExemption(
|
||||||
data.length,
|
data.length,
|
||||||
);
|
);
|
||||||
const from = await newAccountWithLamports(
|
|
||||||
|
const from = new Account();
|
||||||
|
await helpers.airdrop({
|
||||||
connection,
|
connection,
|
||||||
payerBalance + fees + executableBalance,
|
address: from.publicKey,
|
||||||
);
|
amount: payerBalance + fees + executableBalance,
|
||||||
|
});
|
||||||
|
|
||||||
const program = new Account();
|
const program = new Account();
|
||||||
await BpfLoader.load(connection, from, program, data, BPF_LOADER_PROGRAM_ID);
|
await BpfLoader.load(
|
||||||
|
connection,
|
||||||
|
from,
|
||||||
|
program,
|
||||||
|
data,
|
||||||
|
BPF_LOADER_PROGRAM_ID,
|
||||||
|
);
|
||||||
|
|
||||||
// Check that program loading costed exactly `fees + executableBalance`
|
// Check that program loading costed exactly `fees + executableBalance`
|
||||||
const fromBalance = await connection.getBalance(from.publicKey);
|
const fromBalance = await connection.getBalance(from.publicKey);
|
||||||
expect(fromBalance).toEqual(payerBalance);
|
expect(fromBalance).to.eq(payerBalance);
|
||||||
|
|
||||||
const transaction = new Transaction().add({
|
const transaction = new Transaction().add({
|
||||||
keys: [{pubkey: from.publicKey, isSigner: true, isWritable: true}],
|
keys: [{pubkey: from.publicKey, isSigner: true, isWritable: true}],
|
||||||
@ -56,21 +62,17 @@ test('load BPF C program', async () => {
|
|||||||
commitment: 'singleGossip',
|
commitment: 'singleGossip',
|
||||||
preflightCommitment: 'singleGossip',
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
});
|
||||||
});
|
}).timeout(5000);
|
||||||
|
|
||||||
describe('load BPF Rust program', () => {
|
describe('load BPF Rust program', () => {
|
||||||
if (mockRpcEnabled) {
|
|
||||||
console.log('non-live test skipped');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const connection = new Connection(url, 'singleGossip');
|
const connection = new Connection(url, 'singleGossip');
|
||||||
|
|
||||||
let program: Account;
|
let program = new Account();
|
||||||
let payerAccount: Account;
|
let payerAccount = new Account();
|
||||||
let programData: Buffer;
|
let programData: Buffer;
|
||||||
|
|
||||||
beforeAll(async () => {
|
before(async function () {
|
||||||
|
this.timeout(60_000);
|
||||||
programData = await fs.readFile(
|
programData = await fs.readFile(
|
||||||
'test/fixtures/noop-rust/solana_bpf_rust_noop.so',
|
'test/fixtures/noop-rust/solana_bpf_rust_noop.so',
|
||||||
);
|
);
|
||||||
@ -79,24 +81,33 @@ describe('load BPF Rust program', () => {
|
|||||||
const fees =
|
const fees =
|
||||||
feeCalculator.lamportsPerSignature *
|
feeCalculator.lamportsPerSignature *
|
||||||
BpfLoader.getMinNumSignatures(programData.length);
|
BpfLoader.getMinNumSignatures(programData.length);
|
||||||
const payerBalance = await connection.getMinimumBalanceForRentExemption(0);
|
const payerBalance = await connection.getMinimumBalanceForRentExemption(
|
||||||
|
0,
|
||||||
|
);
|
||||||
const executableBalance = await connection.getMinimumBalanceForRentExemption(
|
const executableBalance = await connection.getMinimumBalanceForRentExemption(
|
||||||
programData.length,
|
programData.length,
|
||||||
);
|
);
|
||||||
|
|
||||||
payerAccount = await newAccountWithLamports(
|
await helpers.airdrop({
|
||||||
connection,
|
connection,
|
||||||
payerBalance + fees + executableBalance,
|
address: payerAccount.publicKey,
|
||||||
);
|
amount: payerBalance + fees + executableBalance,
|
||||||
|
});
|
||||||
|
|
||||||
// Create program account with low balance
|
// Create program account with low balance
|
||||||
program = await newAccountWithLamports(connection, executableBalance - 1);
|
await helpers.airdrop({
|
||||||
|
connection,
|
||||||
|
address: program.publicKey,
|
||||||
|
amount: executableBalance - 1,
|
||||||
|
});
|
||||||
|
|
||||||
// First load will fail part way due to lack of funds
|
// First load will fail part way due to lack of funds
|
||||||
const insufficientPayerAccount = await newAccountWithLamports(
|
const insufficientPayerAccount = new Account();
|
||||||
|
await helpers.airdrop({
|
||||||
connection,
|
connection,
|
||||||
2 * feeCalculator.lamportsPerSignature * 8,
|
address: insufficientPayerAccount.publicKey,
|
||||||
);
|
amount: 2 * feeCalculator.lamportsPerSignature * 8,
|
||||||
|
});
|
||||||
|
|
||||||
const failedLoad = BpfLoader.load(
|
const failedLoad = BpfLoader.load(
|
||||||
connection,
|
connection,
|
||||||
@ -105,7 +116,7 @@ describe('load BPF Rust program', () => {
|
|||||||
programData,
|
programData,
|
||||||
BPF_LOADER_PROGRAM_ID,
|
BPF_LOADER_PROGRAM_ID,
|
||||||
);
|
);
|
||||||
await expect(failedLoad).rejects.toThrow();
|
await expect(failedLoad).to.be.rejected;
|
||||||
|
|
||||||
// Second load will succeed
|
// Second load will succeed
|
||||||
await BpfLoader.load(
|
await BpfLoader.load(
|
||||||
@ -117,7 +128,7 @@ describe('load BPF Rust program', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('get confirmed transaction', async () => {
|
it('get confirmed transaction', async () => {
|
||||||
const transaction = new Transaction().add({
|
const transaction = new Transaction().add({
|
||||||
keys: [
|
keys: [
|
||||||
{pubkey: payerAccount.publicKey, isSigner: true, isWritable: true},
|
{pubkey: payerAccount.publicKey, isSigner: true, isWritable: true},
|
||||||
@ -135,23 +146,25 @@ describe('load BPF Rust program', () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const parsedTx = await connection.getParsedConfirmedTransaction(signature);
|
const parsedTx = await connection.getParsedConfirmedTransaction(
|
||||||
|
signature,
|
||||||
|
);
|
||||||
if (parsedTx === null) {
|
if (parsedTx === null) {
|
||||||
expect(parsedTx).not.toBeNull();
|
expect(parsedTx).not.to.be.null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const {signatures, message} = parsedTx.transaction;
|
const {signatures, message} = parsedTx.transaction;
|
||||||
expect(signatures[0]).toEqual(signature);
|
expect(signatures[0]).to.eq(signature);
|
||||||
const ix = message.instructions[0];
|
const ix = message.instructions[0];
|
||||||
if (ix.parsed) {
|
if (ix.parsed) {
|
||||||
expect('parsed' in ix).toBe(false);
|
expect('parsed' in ix).to.eq(false);
|
||||||
} else {
|
} else {
|
||||||
expect(ix.programId.equals(program.publicKey)).toBe(true);
|
expect(ix.programId).to.eql(program.publicKey);
|
||||||
expect(ix.data).toEqual('');
|
expect(ix.data).to.eq('');
|
||||||
}
|
}
|
||||||
});
|
}).timeout(30000);
|
||||||
|
|
||||||
test('simulate transaction', async () => {
|
it('simulate transaction', async () => {
|
||||||
const simulatedTransaction = new Transaction().add({
|
const simulatedTransaction = new Transaction().add({
|
||||||
keys: [
|
keys: [
|
||||||
{pubkey: payerAccount.publicKey, isSigner: true, isWritable: true},
|
{pubkey: payerAccount.publicKey, isSigner: true, isWritable: true},
|
||||||
@ -160,25 +173,27 @@ describe('load BPF Rust program', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const {err, logs} = (
|
const {err, logs} = (
|
||||||
await connection.simulateTransaction(simulatedTransaction, [payerAccount])
|
await connection.simulateTransaction(simulatedTransaction, [
|
||||||
|
payerAccount,
|
||||||
|
])
|
||||||
).value;
|
).value;
|
||||||
expect(err).toBeNull();
|
expect(err).to.be.null;
|
||||||
|
|
||||||
if (logs === null) {
|
if (logs === null) {
|
||||||
expect(logs).not.toBeNull();
|
expect(logs).not.to.be.null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(logs.length).toBeGreaterThanOrEqual(2);
|
expect(logs.length).to.be.at.least(2);
|
||||||
expect(logs[0]).toEqual(
|
expect(logs[0]).to.eq(
|
||||||
`Program ${program.publicKey.toBase58()} invoke [1]`,
|
`Program ${program.publicKey.toBase58()} invoke [1]`,
|
||||||
);
|
);
|
||||||
expect(logs[logs.length - 1]).toEqual(
|
expect(logs[logs.length - 1]).to.eq(
|
||||||
`Program ${program.publicKey.toBase58()} success`,
|
`Program ${program.publicKey.toBase58()} success`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('deprecated - simulate transaction without signature verification', async () => {
|
it('deprecated - simulate transaction without signature verification', async () => {
|
||||||
const simulatedTransaction = new Transaction().add({
|
const simulatedTransaction = new Transaction().add({
|
||||||
keys: [
|
keys: [
|
||||||
{pubkey: payerAccount.publicKey, isSigner: true, isWritable: true},
|
{pubkey: payerAccount.publicKey, isSigner: true, isWritable: true},
|
||||||
@ -190,23 +205,23 @@ describe('load BPF Rust program', () => {
|
|||||||
const {err, logs} = (
|
const {err, logs} = (
|
||||||
await connection.simulateTransaction(simulatedTransaction)
|
await connection.simulateTransaction(simulatedTransaction)
|
||||||
).value;
|
).value;
|
||||||
expect(err).toBeNull();
|
expect(err).to.be.null;
|
||||||
|
|
||||||
if (logs === null) {
|
if (logs === null) {
|
||||||
expect(logs).not.toBeNull();
|
expect(logs).not.to.be.null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(logs.length).toBeGreaterThanOrEqual(2);
|
expect(logs.length).to.be.at.least(2);
|
||||||
expect(logs[0]).toEqual(
|
expect(logs[0]).to.eq(
|
||||||
`Program ${program.publicKey.toBase58()} invoke [1]`,
|
`Program ${program.publicKey.toBase58()} invoke [1]`,
|
||||||
);
|
);
|
||||||
expect(logs[logs.length - 1]).toEqual(
|
expect(logs[logs.length - 1]).to.eq(
|
||||||
`Program ${program.publicKey.toBase58()} success`,
|
`Program ${program.publicKey.toBase58()} success`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('simulate transaction without signature verification', async () => {
|
it('simulate transaction without signature verification', async () => {
|
||||||
const simulatedTransaction = new Transaction({
|
const simulatedTransaction = new Transaction({
|
||||||
feePayer: payerAccount.publicKey,
|
feePayer: payerAccount.publicKey,
|
||||||
}).add({
|
}).add({
|
||||||
@ -219,23 +234,23 @@ describe('load BPF Rust program', () => {
|
|||||||
const {err, logs} = (
|
const {err, logs} = (
|
||||||
await connection.simulateTransaction(simulatedTransaction)
|
await connection.simulateTransaction(simulatedTransaction)
|
||||||
).value;
|
).value;
|
||||||
expect(err).toBeNull();
|
expect(err).to.be.null;
|
||||||
|
|
||||||
if (logs === null) {
|
if (logs === null) {
|
||||||
expect(logs).not.toBeNull();
|
expect(logs).not.to.be.null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(logs.length).toBeGreaterThanOrEqual(2);
|
expect(logs.length).to.be.at.least(2);
|
||||||
expect(logs[0]).toEqual(
|
expect(logs[0]).to.eq(
|
||||||
`Program ${program.publicKey.toBase58()} invoke [1]`,
|
`Program ${program.publicKey.toBase58()} invoke [1]`,
|
||||||
);
|
);
|
||||||
expect(logs[logs.length - 1]).toEqual(
|
expect(logs[logs.length - 1]).to.eq(
|
||||||
`Program ${program.publicKey.toBase58()} success`,
|
`Program ${program.publicKey.toBase58()} success`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('simulate transaction with bad programId', async () => {
|
it('simulate transaction with bad programId', async () => {
|
||||||
const simulatedTransaction = new Transaction().add({
|
const simulatedTransaction = new Transaction().add({
|
||||||
keys: [
|
keys: [
|
||||||
{pubkey: payerAccount.publicKey, isSigner: true, isWritable: true},
|
{pubkey: payerAccount.publicKey, isSigner: true, isWritable: true},
|
||||||
@ -247,17 +262,17 @@ describe('load BPF Rust program', () => {
|
|||||||
const {err, logs} = (
|
const {err, logs} = (
|
||||||
await connection.simulateTransaction(simulatedTransaction)
|
await connection.simulateTransaction(simulatedTransaction)
|
||||||
).value;
|
).value;
|
||||||
expect(err).toEqual('ProgramAccountNotFound');
|
expect(err).to.eq('ProgramAccountNotFound');
|
||||||
|
|
||||||
if (logs === null) {
|
if (logs === null) {
|
||||||
expect(logs).not.toBeNull();
|
expect(logs).not.to.be.null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(logs.length).toEqual(0);
|
expect(logs).to.have.length(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('reload program', async () => {
|
it('reload program', async () => {
|
||||||
expect(
|
expect(
|
||||||
await BpfLoader.load(
|
await BpfLoader.load(
|
||||||
connection,
|
connection,
|
||||||
@ -266,6 +281,8 @@ describe('load BPF Rust program', () => {
|
|||||||
programData,
|
programData,
|
||||||
BPF_LOADER_PROGRAM_ID,
|
BPF_LOADER_PROGRAM_ID,
|
||||||
),
|
),
|
||||||
).toBe(false);
|
).to.eq(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import {clusterApiUrl} from '../src/util/cluster';
|
import {clusterApiUrl} from '../src/util/cluster';
|
||||||
|
import {expect} from 'chai';
|
||||||
|
|
||||||
test('invalid', () => {
|
describe('Cluster Util', () => {
|
||||||
|
it('invalid', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
// $FlowExpectedError
|
// $FlowExpectedError
|
||||||
clusterApiUrl('abc123');
|
clusterApiUrl('abc123');
|
||||||
}).toThrow();
|
}).to.throw();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('devnet', () => {
|
it('devnet', () => {
|
||||||
expect(clusterApiUrl()).toEqual('https://devnet.solana.com');
|
expect(clusterApiUrl()).to.eq('https://devnet.solana.com');
|
||||||
expect(clusterApiUrl('devnet')).toEqual('https://devnet.solana.com');
|
expect(clusterApiUrl('devnet')).to.eq('https://devnet.solana.com');
|
||||||
expect(clusterApiUrl('devnet', true)).toEqual('https://devnet.solana.com');
|
expect(clusterApiUrl('devnet', true)).to.eq('https://devnet.solana.com');
|
||||||
expect(clusterApiUrl('devnet', false)).toEqual('http://devnet.solana.com');
|
expect(clusterApiUrl('devnet', false)).to.eq('http://devnet.solana.com');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
File diff suppressed because it is too large
Load Diff
7
web3.js/test/fixtures/noop-c/build.sh
vendored
7
web3.js/test/fixtures/noop-c/build.sh
vendored
@ -1,7 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
make -C ../../../examples/bpf-c-noop/
|
|
||||||
cp ../../../examples/bpf-c-noop/out/noop.so .
|
|
7
web3.js/test/fixtures/noop-rust/build.sh
vendored
7
web3.js/test/fixtures/noop-rust/build.sh
vendored
@ -1,7 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
cargo build-bpf --manifest-path=../../../examples/bpf-rust-noop/Cargo.toml
|
|
||||||
cp ../../../examples/bpf-rust-noop/target/deploy/solana_bpf_rust_noop.so .
|
|
@ -1,83 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import {Account} from '../src/account';
|
|
||||||
import {SystemProgram} from '../src/system-program';
|
|
||||||
import {Transaction} from '../src/transaction';
|
|
||||||
|
|
||||||
test('verify getConfirmedBlock', () => {
|
|
||||||
const account0 = new Account();
|
|
||||||
const account1 = new Account();
|
|
||||||
const account2 = new Account();
|
|
||||||
const account3 = new Account();
|
|
||||||
const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
|
|
||||||
|
|
||||||
// Create a couple signed transactions
|
|
||||||
const transfer0 = SystemProgram.transfer({
|
|
||||||
fromPubkey: account0.publicKey,
|
|
||||||
toPubkey: account1.publicKey,
|
|
||||||
lamports: 123,
|
|
||||||
});
|
|
||||||
|
|
||||||
const transaction0 = new Transaction({recentBlockhash}).add(transfer0);
|
|
||||||
transaction0.sign(account0);
|
|
||||||
const transfer1 = SystemProgram.transfer({
|
|
||||||
fromPubkey: account2.publicKey,
|
|
||||||
toPubkey: account3.publicKey,
|
|
||||||
lamports: 456,
|
|
||||||
});
|
|
||||||
|
|
||||||
let transaction1 = new Transaction({recentBlockhash}).add(transfer1);
|
|
||||||
transaction1.sign(account2);
|
|
||||||
|
|
||||||
// Build ConfirmedBlock, with dummy data for blockhashes, balances
|
|
||||||
const confirmedBlock = {
|
|
||||||
blockhash: recentBlockhash,
|
|
||||||
previousBlockhash: recentBlockhash,
|
|
||||||
transactions: [
|
|
||||||
{
|
|
||||||
transaction: transaction0,
|
|
||||||
meta: {
|
|
||||||
fee: 0,
|
|
||||||
preBalances: [100000, 100000, 1, 1, 1],
|
|
||||||
postBalances: [99877, 100123, 1, 1, 1],
|
|
||||||
status: {Ok: null},
|
|
||||||
err: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
transaction: transaction1,
|
|
||||||
meta: {
|
|
||||||
fee: 0,
|
|
||||||
preBalances: [100000, 100000, 1, 1, 1],
|
|
||||||
postBalances: [99544, 100456, 1, 1, 1],
|
|
||||||
status: {Ok: null},
|
|
||||||
err: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
rewards: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
// Verify signatures in ConfirmedBlock
|
|
||||||
for (const transactionWithMeta of confirmedBlock.transactions) {
|
|
||||||
expect(transactionWithMeta.transaction.verifySignatures()).toBe(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const bogusSignature = {
|
|
||||||
signature: Buffer.alloc(64, 9),
|
|
||||||
publicKey: account2.publicKey,
|
|
||||||
};
|
|
||||||
transaction1.signatures[0] = bogusSignature;
|
|
||||||
|
|
||||||
let badConfirmedBlock = confirmedBlock;
|
|
||||||
badConfirmedBlock.transactions[1].transaction = transaction1;
|
|
||||||
|
|
||||||
// Verify signatures in ConfirmedBlock
|
|
||||||
const verifications = badConfirmedBlock.transactions.map(
|
|
||||||
transactionWithMeta => transactionWithMeta.transaction.verifySignatures(),
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
verifications.reduce(
|
|
||||||
(accumulator, currentValue) => accumulator && currentValue,
|
|
||||||
),
|
|
||||||
).toBe(false);
|
|
||||||
});
|
|
@ -1,19 +0,0 @@
|
|||||||
// @flow
|
|
||||||
|
|
||||||
import type {TransactionSignature} from '../../src/transaction';
|
|
||||||
import {mockRpcSocket} from '../__mocks__/rpc-websockets';
|
|
||||||
|
|
||||||
export function mockConfirmTransaction(signature: TransactionSignature) {
|
|
||||||
mockRpcSocket.push([
|
|
||||||
{
|
|
||||||
method: 'signatureSubscribe',
|
|
||||||
params: [signature, {commitment: 'singleGossip'}],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
context: {
|
|
||||||
slot: 11,
|
|
||||||
},
|
|
||||||
value: {err: null},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
// @flow
|
|
||||||
|
|
||||||
import {Account} from '../../src';
|
|
||||||
import type {Commitment} from '../../src/connection';
|
|
||||||
import {url} from '../url';
|
|
||||||
import {mockRpc} from '../__mocks__/node-fetch';
|
|
||||||
|
|
||||||
export function mockGetRecentBlockhash(commitment: ?Commitment) {
|
|
||||||
const recentBlockhash = new Account();
|
|
||||||
const params = [];
|
|
||||||
if (commitment) {
|
|
||||||
params.push({commitment});
|
|
||||||
}
|
|
||||||
|
|
||||||
mockRpc.push([
|
|
||||||
url,
|
|
||||||
{
|
|
||||||
method: 'getRecentBlockhash',
|
|
||||||
params,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result: {
|
|
||||||
context: {
|
|
||||||
slot: 11,
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
blockhash: recentBlockhash.publicKey.toBase58(),
|
|
||||||
feeCalculator: {
|
|
||||||
lamportsPerSignature: 42,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
170
web3.js/test/mocks/rpc-http.js
Normal file
170
web3.js/test/mocks/rpc-http.js
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import bs58 from 'bs58';
|
||||||
|
import BN from 'bn.js';
|
||||||
|
import * as mockttp from 'mockttp';
|
||||||
|
import {mockRpcMessage} from './rpc-websockets';
|
||||||
|
|
||||||
|
import {Connection} from '../../src';
|
||||||
|
import type {Commitment} from '../../src/connection';
|
||||||
|
|
||||||
|
export const mockServer = process.env.TEST_LIVE || mockttp.getLocal();
|
||||||
|
|
||||||
|
let uniqueCounter = 0;
|
||||||
|
export const uniqueSignature = () => {
|
||||||
|
return bs58.encode(new BN(++uniqueCounter).toArray(null, 64));
|
||||||
|
};
|
||||||
|
export const uniqueBlockhash = () => {
|
||||||
|
return bs58.encode(new BN(++uniqueCounter).toArray(null, 32));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mockErrorMessage = 'Invalid';
|
||||||
|
export const mockErrorResponse = {
|
||||||
|
code: -32602,
|
||||||
|
message: mockErrorMessage,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mockRpcResponse = async ({
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
value,
|
||||||
|
error,
|
||||||
|
withContext,
|
||||||
|
}: {
|
||||||
|
method: string,
|
||||||
|
params: Array<any>,
|
||||||
|
value: any,
|
||||||
|
error: any,
|
||||||
|
withContext?: boolean,
|
||||||
|
}) => {
|
||||||
|
if (process.env.TEST_LIVE) return;
|
||||||
|
let result = withContext
|
||||||
|
? {
|
||||||
|
context: {
|
||||||
|
slot: 11,
|
||||||
|
},
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
: value;
|
||||||
|
await mockServer
|
||||||
|
.post('/')
|
||||||
|
.withJsonBodyIncluding({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
})
|
||||||
|
.thenReply(
|
||||||
|
200,
|
||||||
|
JSON.stringify({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
id: '',
|
||||||
|
error,
|
||||||
|
result,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const recentBlockhash = async ({
|
||||||
|
connection,
|
||||||
|
commitment,
|
||||||
|
}: {
|
||||||
|
connection: Connection,
|
||||||
|
commitment: ?Commitment,
|
||||||
|
}) => {
|
||||||
|
const blockhash = uniqueBlockhash();
|
||||||
|
const params = [];
|
||||||
|
if (commitment) {
|
||||||
|
params.push({commitment});
|
||||||
|
}
|
||||||
|
|
||||||
|
await mockRpcResponse({
|
||||||
|
method: 'getRecentBlockhash',
|
||||||
|
params,
|
||||||
|
value: {
|
||||||
|
blockhash,
|
||||||
|
feeCalculator: {
|
||||||
|
lamportsPerSignature: 42,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
withContext: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return await connection.getRecentBlockhash(commitment);
|
||||||
|
};
|
||||||
|
|
||||||
|
const processTransaction = async ({
|
||||||
|
connection,
|
||||||
|
transaction,
|
||||||
|
signers,
|
||||||
|
commitment,
|
||||||
|
err,
|
||||||
|
}: {
|
||||||
|
connection: Connection,
|
||||||
|
transaction: Transaction,
|
||||||
|
signers: Array<Account>,
|
||||||
|
commitment: Commitment,
|
||||||
|
err?: any,
|
||||||
|
}) => {
|
||||||
|
const blockhash = (await recentBlockhash({connection})).blockhash;
|
||||||
|
transaction.recentBlockhash = blockhash;
|
||||||
|
transaction.sign(...signers);
|
||||||
|
|
||||||
|
const encoded = transaction.serialize().toString('base64');
|
||||||
|
const signature = bs58.encode(transaction.signature);
|
||||||
|
await mockRpcResponse({
|
||||||
|
method: 'sendTransaction',
|
||||||
|
params: [encoded],
|
||||||
|
value: signature,
|
||||||
|
});
|
||||||
|
|
||||||
|
const sendOptions = err
|
||||||
|
? {
|
||||||
|
skipPreflight: true,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
preflightCommitment: commitment,
|
||||||
|
};
|
||||||
|
|
||||||
|
await connection.sendEncodedTransaction(encoded, sendOptions);
|
||||||
|
|
||||||
|
await mockRpcMessage({
|
||||||
|
method: 'signatureSubscribe',
|
||||||
|
params: [signature, {commitment}],
|
||||||
|
result: {err: err || null},
|
||||||
|
});
|
||||||
|
|
||||||
|
return await connection.confirmTransaction(signature, commitment);
|
||||||
|
};
|
||||||
|
|
||||||
|
const airdrop = async ({
|
||||||
|
connection,
|
||||||
|
address,
|
||||||
|
amount,
|
||||||
|
}: {
|
||||||
|
connection: Connection,
|
||||||
|
address: PublicKey,
|
||||||
|
amount: number,
|
||||||
|
}) => {
|
||||||
|
await mockRpcResponse({
|
||||||
|
method: 'requestAirdrop',
|
||||||
|
params: [address.toBase58(), amount],
|
||||||
|
value: uniqueSignature(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const signature = await connection.requestAirdrop(address, amount);
|
||||||
|
|
||||||
|
await mockRpcMessage({
|
||||||
|
method: 'signatureSubscribe',
|
||||||
|
params: [signature, {commitment: 'singleGossip'}],
|
||||||
|
result: {err: null},
|
||||||
|
});
|
||||||
|
|
||||||
|
await connection.confirmTransaction(signature, 'singleGossip');
|
||||||
|
return signature;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const helpers = {
|
||||||
|
airdrop,
|
||||||
|
processTransaction,
|
||||||
|
recentBlockhash,
|
||||||
|
};
|
106
web3.js/test/mocks/rpc-websockets.js
Normal file
106
web3.js/test/mocks/rpc-websockets.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import {Client as LiveClient} from 'rpc-websockets';
|
||||||
|
import {expect} from 'chai';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
import {Connection} from '../../src';
|
||||||
|
|
||||||
|
type RpcRequest = {
|
||||||
|
method: string,
|
||||||
|
params?: Array<any>,
|
||||||
|
};
|
||||||
|
|
||||||
|
type RpcResponse = {
|
||||||
|
context: {
|
||||||
|
slot: number,
|
||||||
|
},
|
||||||
|
value: any,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockRpcSocket: Array<[RpcRequest, RpcResponse]> = [];
|
||||||
|
const sandbox = sinon.createSandbox();
|
||||||
|
|
||||||
|
export const mockRpcMessage = ({
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
result,
|
||||||
|
}: {
|
||||||
|
method: string,
|
||||||
|
params: Array<any>,
|
||||||
|
result: any,
|
||||||
|
}) => {
|
||||||
|
mockRpcSocket.push([
|
||||||
|
{method, params},
|
||||||
|
{
|
||||||
|
context: {slot: 11},
|
||||||
|
value: result,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const stubRpcWebSocket = (connection: Connection) => {
|
||||||
|
const rpcWebSocket = connection._rpcWebSocket;
|
||||||
|
const mockClient = new MockClient(rpcWebSocket);
|
||||||
|
sandbox.stub(rpcWebSocket, 'connect').callsFake(() => {
|
||||||
|
mockClient.connect();
|
||||||
|
});
|
||||||
|
sandbox.stub(rpcWebSocket, 'close').callsFake(() => {
|
||||||
|
mockClient.close();
|
||||||
|
});
|
||||||
|
sandbox.stub(rpcWebSocket, 'call').callsFake((method, params) => {
|
||||||
|
return mockClient.call(method, params);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const restoreRpcWebSocket = (connection: Connection) => {
|
||||||
|
connection._rpcWebSocket.close();
|
||||||
|
if (connection._rpcWebSocketIdleTimeout !== null) {
|
||||||
|
clearTimeout(connection._rpcWebSocketIdleTimeout);
|
||||||
|
connection._rpcWebSocketIdleTimeout = null;
|
||||||
|
}
|
||||||
|
sandbox.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockClient {
|
||||||
|
mockOpen = false;
|
||||||
|
subscriptionCounter = 0;
|
||||||
|
|
||||||
|
constructor(rpcWebSocket: LiveClient) {
|
||||||
|
this.client = rpcWebSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
if (!this.mockOpen) {
|
||||||
|
this.mockOpen = true;
|
||||||
|
this.client.emit('open');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
if (this.mockOpen) {
|
||||||
|
this.mockOpen = false;
|
||||||
|
this.client.emit('close');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
call(method: string, params: Array<any>): Promise<Object> {
|
||||||
|
expect(mockRpcSocket.length).to.be.at.least(1);
|
||||||
|
const [mockRequest, mockResponse] = mockRpcSocket.shift();
|
||||||
|
|
||||||
|
expect(method).to.eq(mockRequest.method);
|
||||||
|
expect(params).to.eql(mockRequest.params);
|
||||||
|
|
||||||
|
let id = ++this.subscriptionCounter;
|
||||||
|
const response = {
|
||||||
|
subscription: id,
|
||||||
|
result: mockResponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
setImmediate(() => {
|
||||||
|
const eventName = method.replace('Subscribe', 'Notification');
|
||||||
|
this.client.emit(eventName, response);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.resolve(id);
|
||||||
|
}
|
||||||
|
}
|
@ -1,36 +0,0 @@
|
|||||||
// @flow
|
|
||||||
|
|
||||||
import {Account, Connection} from '../src';
|
|
||||||
import {mockRpc} from './__mocks__/node-fetch';
|
|
||||||
import {url} from './url';
|
|
||||||
|
|
||||||
export async function newAccountWithLamports(
|
|
||||||
connection: Connection,
|
|
||||||
lamports: number = 1000000,
|
|
||||||
): Promise<Account> {
|
|
||||||
const account = new Account();
|
|
||||||
|
|
||||||
{
|
|
||||||
mockRpc.push([
|
|
||||||
url,
|
|
||||||
{
|
|
||||||
method: 'requestAirdrop',
|
|
||||||
params: [account.publicKey.toBase58(), lamports],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
// Signature doesn't matter
|
|
||||||
result:
|
|
||||||
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const signature = await connection.requestAirdrop(
|
|
||||||
account.publicKey,
|
|
||||||
lamports,
|
|
||||||
);
|
|
||||||
await connection.confirmTransaction(signature, 'singleGossip');
|
|
||||||
|
|
||||||
return account;
|
|
||||||
}
|
|
@ -1,6 +1,8 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import bs58 from 'bs58';
|
import bs58 from 'bs58';
|
||||||
|
import {Buffer} from 'buffer';
|
||||||
|
import {expect} from 'chai';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Account,
|
Account,
|
||||||
@ -10,15 +12,9 @@ import {
|
|||||||
PublicKey,
|
PublicKey,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
import {NONCE_ACCOUNT_LENGTH} from '../src/nonce-account';
|
import {NONCE_ACCOUNT_LENGTH} from '../src/nonce-account';
|
||||||
import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
|
import {MOCK_PORT, url} from './url';
|
||||||
import {mockGetRecentBlockhash} from './mockrpc/get-recent-blockhash';
|
import {helpers, mockRpcResponse, mockServer} from './mocks/rpc-http';
|
||||||
import {url} from './url';
|
import {stubRpcWebSocket, restoreRpcWebSocket} from './mocks/rpc-websockets';
|
||||||
import {mockConfirmTransaction} from './mockrpc/confirm-transaction';
|
|
||||||
|
|
||||||
if (!mockRpcEnabled) {
|
|
||||||
// Testing max commitment level takes around 20s to complete
|
|
||||||
jest.setTimeout(30000);
|
|
||||||
}
|
|
||||||
|
|
||||||
const expectedData = (authorizedPubkey: PublicKey): [string, string] => {
|
const expectedData = (authorizedPubkey: PublicKey): [string, string] => {
|
||||||
const expectedData = Buffer.alloc(NONCE_ACCOUNT_LENGTH);
|
const expectedData = Buffer.alloc(NONCE_ACCOUNT_LENGTH);
|
||||||
@ -31,79 +27,43 @@ const expectedData = (authorizedPubkey: PublicKey): [string, string] => {
|
|||||||
return [expectedData.toString('base64'), 'base64'];
|
return [expectedData.toString('base64'), 'base64'];
|
||||||
};
|
};
|
||||||
|
|
||||||
test('create and query nonce account', async () => {
|
describe('Nonce', () => {
|
||||||
|
let connection: Connection;
|
||||||
|
beforeEach(() => {
|
||||||
|
connection = new Connection(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!process.env.TEST_LIVE) {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockServer.start(MOCK_PORT);
|
||||||
|
stubRpcWebSocket(connection);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
mockServer.stop();
|
||||||
|
restoreRpcWebSocket(connection);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
it('create and query nonce account', async () => {
|
||||||
const from = new Account();
|
const from = new Account();
|
||||||
const nonceAccount = new Account();
|
const nonceAccount = new Account();
|
||||||
const connection = new Connection(url, 'singleGossip');
|
|
||||||
|
|
||||||
mockRpc.push([
|
await mockRpcResponse({
|
||||||
url,
|
|
||||||
{
|
|
||||||
method: 'getMinimumBalanceForRentExemption',
|
method: 'getMinimumBalanceForRentExemption',
|
||||||
params: [NONCE_ACCOUNT_LENGTH, {commitment: 'singleGossip'}],
|
params: [NONCE_ACCOUNT_LENGTH],
|
||||||
},
|
value: 50,
|
||||||
{
|
});
|
||||||
error: null,
|
|
||||||
result: 50,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
||||||
NONCE_ACCOUNT_LENGTH,
|
NONCE_ACCOUNT_LENGTH,
|
||||||
);
|
);
|
||||||
|
|
||||||
mockRpc.push([
|
await helpers.airdrop({
|
||||||
url,
|
connection,
|
||||||
{
|
address: from.publicKey,
|
||||||
method: 'requestAirdrop',
|
amount: minimumAmount * 2,
|
||||||
params: [from.publicKey.toBase58(), minimumAmount * 2],
|
});
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result:
|
|
||||||
'1WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const signature = await connection.requestAirdrop(
|
|
||||||
from.publicKey,
|
|
||||||
minimumAmount * 2,
|
|
||||||
);
|
|
||||||
mockConfirmTransaction(signature);
|
|
||||||
await connection.confirmTransaction(signature, 'singleGossip');
|
|
||||||
|
|
||||||
mockRpc.push([
|
|
||||||
url,
|
|
||||||
{
|
|
||||||
method: 'getBalance',
|
|
||||||
params: [from.publicKey.toBase58(), {commitment: 'singleGossip'}],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result: {
|
|
||||||
context: {
|
|
||||||
slot: 11,
|
|
||||||
},
|
|
||||||
value: minimumAmount * 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const balance = await connection.getBalance(from.publicKey);
|
|
||||||
expect(balance).toBe(minimumAmount * 2);
|
|
||||||
|
|
||||||
mockGetRecentBlockhash('max');
|
|
||||||
mockRpc.push([
|
|
||||||
url,
|
|
||||||
{
|
|
||||||
method: 'sendTransaction',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result:
|
|
||||||
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const transaction = new Transaction().add(
|
const transaction = new Transaction().add(
|
||||||
SystemProgram.createNonceAccount({
|
SystemProgram.createNonceAccount({
|
||||||
@ -113,51 +73,42 @@ test('create and query nonce account', async () => {
|
|||||||
lamports: minimumAmount,
|
lamports: minimumAmount,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const nonceSignature = await connection.sendTransaction(
|
|
||||||
transaction,
|
|
||||||
[from, nonceAccount],
|
|
||||||
{
|
|
||||||
skipPreflight: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
mockConfirmTransaction(nonceSignature);
|
|
||||||
await connection.confirmTransaction(nonceSignature, 'singleGossip');
|
|
||||||
|
|
||||||
mockRpc.push([
|
await helpers.processTransaction({
|
||||||
url,
|
connection,
|
||||||
{
|
transaction,
|
||||||
|
signers: [from, nonceAccount],
|
||||||
|
commitment: 'singleGossip',
|
||||||
|
});
|
||||||
|
|
||||||
|
await mockRpcResponse({
|
||||||
method: 'getAccountInfo',
|
method: 'getAccountInfo',
|
||||||
params: [
|
params: [
|
||||||
nonceAccount.publicKey.toBase58(),
|
nonceAccount.publicKey.toBase58(),
|
||||||
{encoding: 'base64', commitment: 'singleGossip'},
|
{encoding: 'base64', commitment: 'singleGossip'},
|
||||||
],
|
],
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result: {
|
|
||||||
context: {
|
|
||||||
slot: 11,
|
|
||||||
},
|
|
||||||
value: {
|
value: {
|
||||||
owner: '11111111111111111111111111111111',
|
owner: '11111111111111111111111111111111',
|
||||||
lamports: minimumAmount,
|
lamports: minimumAmount,
|
||||||
data: expectedData(from.publicKey),
|
data: expectedData(from.publicKey),
|
||||||
executable: false,
|
executable: false,
|
||||||
},
|
},
|
||||||
},
|
withContext: true,
|
||||||
},
|
|
||||||
]);
|
|
||||||
//
|
|
||||||
const nonceAccountData = await connection.getNonce(nonceAccount.publicKey);
|
|
||||||
if (nonceAccountData === null) {
|
|
||||||
expect(nonceAccountData).not.toBeNull();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
expect(nonceAccountData.authorizedPubkey).toEqual(from.publicKey);
|
|
||||||
expect(bs58.decode(nonceAccountData.nonce).length).toBeGreaterThan(30);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('create and query nonce account with seed', async () => {
|
const nonceAccountData = await connection.getNonce(
|
||||||
|
nonceAccount.publicKey,
|
||||||
|
'singleGossip',
|
||||||
|
);
|
||||||
|
if (nonceAccountData === null) {
|
||||||
|
expect(nonceAccountData).not.to.be.null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
expect(nonceAccountData.authorizedPubkey).to.eql(from.publicKey);
|
||||||
|
expect(bs58.decode(nonceAccountData.nonce).length).to.be.greaterThan(30);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('create and query nonce account with seed', async () => {
|
||||||
const from = new Account();
|
const from = new Account();
|
||||||
const seed = 'seed';
|
const seed = 'seed';
|
||||||
const noncePubkey = await PublicKey.createWithSeed(
|
const noncePubkey = await PublicKey.createWithSeed(
|
||||||
@ -165,76 +116,22 @@ test('create and query nonce account with seed', async () => {
|
|||||||
seed,
|
seed,
|
||||||
SystemProgram.programId,
|
SystemProgram.programId,
|
||||||
);
|
);
|
||||||
const connection = new Connection(url, 'singleGossip');
|
|
||||||
|
|
||||||
mockRpc.push([
|
await mockRpcResponse({
|
||||||
url,
|
|
||||||
{
|
|
||||||
method: 'getMinimumBalanceForRentExemption',
|
method: 'getMinimumBalanceForRentExemption',
|
||||||
params: [NONCE_ACCOUNT_LENGTH, {commitment: 'singleGossip'}],
|
params: [NONCE_ACCOUNT_LENGTH],
|
||||||
},
|
value: 50,
|
||||||
{
|
});
|
||||||
error: null,
|
|
||||||
result: 50,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
||||||
NONCE_ACCOUNT_LENGTH,
|
NONCE_ACCOUNT_LENGTH,
|
||||||
);
|
);
|
||||||
|
|
||||||
mockRpc.push([
|
await helpers.airdrop({
|
||||||
url,
|
connection,
|
||||||
{
|
address: from.publicKey,
|
||||||
method: 'requestAirdrop',
|
amount: minimumAmount * 2,
|
||||||
params: [from.publicKey.toBase58(), minimumAmount * 2],
|
});
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result:
|
|
||||||
'1WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const signature = await connection.requestAirdrop(
|
|
||||||
from.publicKey,
|
|
||||||
minimumAmount * 2,
|
|
||||||
);
|
|
||||||
mockConfirmTransaction(signature);
|
|
||||||
await connection.confirmTransaction(signature, 'singleGossip');
|
|
||||||
|
|
||||||
mockRpc.push([
|
|
||||||
url,
|
|
||||||
{
|
|
||||||
method: 'getBalance',
|
|
||||||
params: [from.publicKey.toBase58(), {commitment: 'singleGossip'}],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result: {
|
|
||||||
context: {
|
|
||||||
slot: 11,
|
|
||||||
},
|
|
||||||
value: minimumAmount * 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const balance = await connection.getBalance(from.publicKey);
|
|
||||||
expect(balance).toBe(minimumAmount * 2);
|
|
||||||
|
|
||||||
mockGetRecentBlockhash('max');
|
|
||||||
mockRpc.push([
|
|
||||||
url,
|
|
||||||
{
|
|
||||||
method: 'sendTransaction',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result:
|
|
||||||
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const transaction = new Transaction().add(
|
const transaction = new Transaction().add(
|
||||||
SystemProgram.createNonceAccount({
|
SystemProgram.createNonceAccount({
|
||||||
@ -246,42 +143,38 @@ test('create and query nonce account with seed', async () => {
|
|||||||
lamports: minimumAmount,
|
lamports: minimumAmount,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const nonceSignature = await connection.sendTransaction(transaction, [from], {
|
|
||||||
skipPreflight: true,
|
|
||||||
});
|
|
||||||
mockConfirmTransaction(nonceSignature);
|
|
||||||
await connection.confirmTransaction(nonceSignature, 'singleGossip');
|
|
||||||
|
|
||||||
mockRpc.push([
|
await helpers.processTransaction({
|
||||||
url,
|
connection,
|
||||||
{
|
transaction,
|
||||||
|
signers: [from],
|
||||||
|
commitment: 'singleGossip',
|
||||||
|
});
|
||||||
|
|
||||||
|
await mockRpcResponse({
|
||||||
method: 'getAccountInfo',
|
method: 'getAccountInfo',
|
||||||
params: [
|
params: [
|
||||||
noncePubkey.toBase58(),
|
noncePubkey.toBase58(),
|
||||||
{encoding: 'base64', commitment: 'singleGossip'},
|
{encoding: 'base64', commitment: 'singleGossip'},
|
||||||
],
|
],
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result: {
|
|
||||||
context: {
|
|
||||||
slot: 11,
|
|
||||||
},
|
|
||||||
value: {
|
value: {
|
||||||
owner: '11111111111111111111111111111111',
|
owner: '11111111111111111111111111111111',
|
||||||
lamports: minimumAmount,
|
lamports: minimumAmount,
|
||||||
data: expectedData(from.publicKey),
|
data: expectedData(from.publicKey),
|
||||||
executable: false,
|
executable: false,
|
||||||
},
|
},
|
||||||
},
|
withContext: true,
|
||||||
},
|
});
|
||||||
]);
|
|
||||||
//
|
const nonceAccountData = await connection.getNonce(
|
||||||
const nonceAccountData = await connection.getNonce(noncePubkey);
|
noncePubkey,
|
||||||
|
'singleGossip',
|
||||||
|
);
|
||||||
if (nonceAccountData === null) {
|
if (nonceAccountData === null) {
|
||||||
expect(nonceAccountData).not.toBeNull();
|
expect(nonceAccountData).not.to.be.null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
expect(nonceAccountData.authorizedPubkey).toEqual(from.publicKey);
|
expect(nonceAccountData.authorizedPubkey).to.eql(from.publicKey);
|
||||||
expect(bs58.decode(nonceAccountData.nonce).length).toBeGreaterThan(30);
|
expect(bs58.decode(nonceAccountData.nonce).length).to.be.greaterThan(30);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
|
import {Buffer} from 'buffer';
|
||||||
import {PublicKey, MAX_SEED_LENGTH} from '../src/publickey';
|
import {PublicKey, MAX_SEED_LENGTH} from '../src/publickey';
|
||||||
|
import {expect, use} from 'chai';
|
||||||
|
import chaiAsPromised from 'chai-as-promised';
|
||||||
|
|
||||||
test('invalid', () => {
|
use(chaiAsPromised);
|
||||||
|
|
||||||
|
describe('PublicKey', function () {
|
||||||
|
it('invalid', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
new PublicKey([
|
new PublicKey([
|
||||||
3,
|
3,
|
||||||
@ -40,32 +45,32 @@ test('invalid', () => {
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
]);
|
]);
|
||||||
}).toThrow();
|
}).to.throw();
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
new PublicKey(
|
new PublicKey(
|
||||||
'0x300000000000000000000000000000000000000000000000000000000000000000000',
|
'0x300000000000000000000000000000000000000000000000000000000000000000000',
|
||||||
);
|
);
|
||||||
}).toThrow();
|
}).to.throw();
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
new PublicKey(
|
new PublicKey(
|
||||||
'0x300000000000000000000000000000000000000000000000000000000000000',
|
'0x300000000000000000000000000000000000000000000000000000000000000',
|
||||||
);
|
);
|
||||||
}).toThrow();
|
}).to.throw();
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
new PublicKey(
|
new PublicKey(
|
||||||
'135693854574979916511997248057056142015550763280047535983739356259273198796800000',
|
'135693854574979916511997248057056142015550763280047535983739356259273198796800000',
|
||||||
);
|
);
|
||||||
}).toThrow();
|
}).to.throw();
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
new PublicKey('12345');
|
new PublicKey('12345');
|
||||||
}).toThrow();
|
}).to.throw();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('equals', () => {
|
it('equals', () => {
|
||||||
const arrayKey = new PublicKey([
|
const arrayKey = new PublicKey([
|
||||||
3,
|
3,
|
||||||
0,
|
0,
|
||||||
@ -104,20 +109,20 @@ test('equals', () => {
|
|||||||
'CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3',
|
'CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3',
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(arrayKey.equals(base58Key)).toBe(true);
|
expect(arrayKey.equals(base58Key)).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toBase58', () => {
|
it('toBase58', () => {
|
||||||
const key = new PublicKey('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3');
|
const key = new PublicKey('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3');
|
||||||
expect(key.toBase58()).toBe('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3');
|
expect(key.toBase58()).to.eq('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3');
|
||||||
expect(key.toString()).toBe('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3');
|
expect(key.toString()).to.eq('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3');
|
||||||
|
|
||||||
const key2 = new PublicKey('1111111111111111111111111111BukQL');
|
const key2 = new PublicKey('1111111111111111111111111111BukQL');
|
||||||
expect(key2.toBase58()).toBe('1111111111111111111111111111BukQL');
|
expect(key2.toBase58()).to.eq('1111111111111111111111111111BukQL');
|
||||||
expect(key2.toString()).toBe('1111111111111111111111111111BukQL');
|
expect(key2.toString()).to.eq('1111111111111111111111111111BukQL');
|
||||||
|
|
||||||
const key3 = new PublicKey('11111111111111111111111111111111');
|
const key3 = new PublicKey('11111111111111111111111111111111');
|
||||||
expect(key3.toBase58()).toBe('11111111111111111111111111111111');
|
expect(key3.toBase58()).to.eq('11111111111111111111111111111111');
|
||||||
|
|
||||||
const key4 = new PublicKey([
|
const key4 = new PublicKey([
|
||||||
0,
|
0,
|
||||||
@ -153,24 +158,24 @@ test('toBase58', () => {
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
]);
|
]);
|
||||||
expect(key4.toBase58()).toBe('11111111111111111111111111111111');
|
expect(key4.toBase58()).to.eq('11111111111111111111111111111111');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toBuffer', () => {
|
it('toBuffer', () => {
|
||||||
const key = new PublicKey('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3');
|
const key = new PublicKey('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3');
|
||||||
expect(key.toBuffer()).toHaveLength(32);
|
expect(key.toBuffer()).to.have.length(32);
|
||||||
expect(key.toBase58()).toBe('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3');
|
expect(key.toBase58()).to.eq('CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3');
|
||||||
|
|
||||||
const key2 = new PublicKey('11111111111111111111111111111111');
|
const key2 = new PublicKey('11111111111111111111111111111111');
|
||||||
expect(key2.toBuffer()).toHaveLength(32);
|
expect(key2.toBuffer()).to.have.length(32);
|
||||||
expect(key2.toBase58()).toBe('11111111111111111111111111111111');
|
expect(key2.toBase58()).to.eq('11111111111111111111111111111111');
|
||||||
|
|
||||||
const key3 = new PublicKey(0);
|
const key3 = new PublicKey(0);
|
||||||
expect(key3.toBuffer()).toHaveLength(32);
|
expect(key3.toBuffer()).to.have.length(32);
|
||||||
expect(key3.toBase58()).toBe('11111111111111111111111111111111');
|
expect(key3.toBase58()).to.eq('11111111111111111111111111111111');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('equals (II)', () => {
|
it('equals (II)', () => {
|
||||||
const key1 = new PublicKey([
|
const key1 = new PublicKey([
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -207,10 +212,10 @@ test('equals (II)', () => {
|
|||||||
]);
|
]);
|
||||||
const key2 = new PublicKey(key1.toBuffer());
|
const key2 = new PublicKey(key1.toBuffer());
|
||||||
|
|
||||||
expect(key1.equals(key2)).toBe(true);
|
expect(key1.equals(key2)).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('createWithSeed', async () => {
|
it('createWithSeed', async () => {
|
||||||
const defaultPublicKey = new PublicKey('11111111111111111111111111111111');
|
const defaultPublicKey = new PublicKey('11111111111111111111111111111111');
|
||||||
const derivedKey = await PublicKey.createWithSeed(
|
const derivedKey = await PublicKey.createWithSeed(
|
||||||
defaultPublicKey,
|
defaultPublicKey,
|
||||||
@ -222,10 +227,10 @@ test('createWithSeed', async () => {
|
|||||||
derivedKey.equals(
|
derivedKey.equals(
|
||||||
new PublicKey('9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq'),
|
new PublicKey('9h1HyLCW5dZnBVap8C5egQ9Z6pHyjsh5MNy83iPqqRuq'),
|
||||||
),
|
),
|
||||||
).toBe(true);
|
).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('createProgramAddress', async () => {
|
it('createProgramAddress', async () => {
|
||||||
const programId = new PublicKey(
|
const programId = new PublicKey(
|
||||||
'BPFLoader1111111111111111111111111111111111',
|
'BPFLoader1111111111111111111111111111111111',
|
||||||
);
|
);
|
||||||
@ -241,7 +246,7 @@ test('createProgramAddress', async () => {
|
|||||||
programAddress.equals(
|
programAddress.equals(
|
||||||
new PublicKey('3gF2KMe9KiC6FNVBmfg9i267aMPvK37FewCip4eGBFcT'),
|
new PublicKey('3gF2KMe9KiC6FNVBmfg9i267aMPvK37FewCip4eGBFcT'),
|
||||||
),
|
),
|
||||||
).toBe(true);
|
).to.be.true;
|
||||||
|
|
||||||
programAddress = await PublicKey.createProgramAddress(
|
programAddress = await PublicKey.createProgramAddress(
|
||||||
[Buffer.from('☉', 'utf8')],
|
[Buffer.from('☉', 'utf8')],
|
||||||
@ -251,7 +256,7 @@ test('createProgramAddress', async () => {
|
|||||||
programAddress.equals(
|
programAddress.equals(
|
||||||
new PublicKey('7ytmC1nT1xY4RfxCV2ZgyA7UakC93do5ZdyhdF3EtPj7'),
|
new PublicKey('7ytmC1nT1xY4RfxCV2ZgyA7UakC93do5ZdyhdF3EtPj7'),
|
||||||
),
|
),
|
||||||
).toBe(true);
|
).to.be.true;
|
||||||
|
|
||||||
programAddress = await PublicKey.createProgramAddress(
|
programAddress = await PublicKey.createProgramAddress(
|
||||||
[Buffer.from('Talking', 'utf8'), Buffer.from('Squirrels', 'utf8')],
|
[Buffer.from('Talking', 'utf8'), Buffer.from('Squirrels', 'utf8')],
|
||||||
@ -261,7 +266,7 @@ test('createProgramAddress', async () => {
|
|||||||
programAddress.equals(
|
programAddress.equals(
|
||||||
new PublicKey('HwRVBufQ4haG5XSgpspwKtNd3PC9GM9m1196uJW36vds'),
|
new PublicKey('HwRVBufQ4haG5XSgpspwKtNd3PC9GM9m1196uJW36vds'),
|
||||||
),
|
),
|
||||||
).toBe(true);
|
).to.be.true;
|
||||||
|
|
||||||
programAddress = await PublicKey.createProgramAddress(
|
programAddress = await PublicKey.createProgramAddress(
|
||||||
[publicKey.toBuffer()],
|
[publicKey.toBuffer()],
|
||||||
@ -271,25 +276,27 @@ test('createProgramAddress', async () => {
|
|||||||
programAddress.equals(
|
programAddress.equals(
|
||||||
new PublicKey('GUs5qLUfsEHkcMB9T38vjr18ypEhRuNWiePW2LoK4E3K'),
|
new PublicKey('GUs5qLUfsEHkcMB9T38vjr18ypEhRuNWiePW2LoK4E3K'),
|
||||||
),
|
),
|
||||||
).toBe(true);
|
).to.be.true;
|
||||||
|
|
||||||
const programAddress2 = await PublicKey.createProgramAddress(
|
const programAddress2 = await PublicKey.createProgramAddress(
|
||||||
[Buffer.from('Talking', 'utf8')],
|
[Buffer.from('Talking', 'utf8')],
|
||||||
programId,
|
programId,
|
||||||
);
|
);
|
||||||
expect(programAddress.equals(programAddress2)).toBe(false);
|
expect(programAddress.equals(programAddress2)).to.eq(false);
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
PublicKey.createProgramAddress(
|
PublicKey.createProgramAddress(
|
||||||
[Buffer.alloc(MAX_SEED_LENGTH + 1)],
|
[Buffer.alloc(MAX_SEED_LENGTH + 1)],
|
||||||
programId,
|
programId,
|
||||||
),
|
),
|
||||||
).rejects.toThrow('Max seed length exceeded');
|
).to.be.rejectedWith('Max seed length exceeded');
|
||||||
|
|
||||||
// https://github.com/solana-labs/solana/issues/11950
|
// https://github.com/solana-labs/solana/issues/11950
|
||||||
{
|
{
|
||||||
let seeds = [
|
let seeds = [
|
||||||
new PublicKey('H4snTKK9adiU15gP22ErfZYtro3aqR9BTMXiH3AwiUTQ').toBuffer(),
|
new PublicKey(
|
||||||
|
'H4snTKK9adiU15gP22ErfZYtro3aqR9BTMXiH3AwiUTQ',
|
||||||
|
).toBuffer(),
|
||||||
new BN(2).toArrayLike(Buffer, 'le', 8),
|
new BN(2).toArrayLike(Buffer, 'le', 8),
|
||||||
];
|
];
|
||||||
let programId = new PublicKey(
|
let programId = new PublicKey(
|
||||||
@ -300,11 +307,11 @@ test('createProgramAddress', async () => {
|
|||||||
programAddress.equals(
|
programAddress.equals(
|
||||||
new PublicKey('12rqwuEgBYiGhBrDJStCiqEtzQpTTiZbh7teNVLuYcFA'),
|
new PublicKey('12rqwuEgBYiGhBrDJStCiqEtzQpTTiZbh7teNVLuYcFA'),
|
||||||
),
|
),
|
||||||
).toBe(true);
|
).to.be.true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('findProgramAddress', async () => {
|
it('findProgramAddress', async () => {
|
||||||
const programId = new PublicKey(
|
const programId = new PublicKey(
|
||||||
'BPFLoader1111111111111111111111111111111111',
|
'BPFLoader1111111111111111111111111111111111',
|
||||||
);
|
);
|
||||||
@ -319,5 +326,6 @@ test('findProgramAddress', async () => {
|
|||||||
programId,
|
programId,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).toBe(true);
|
).to.be.true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
76
web3.js/test/rollup.config.js
Normal file
76
web3.js/test/rollup.config.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import alias from '@rollup/plugin-alias';
|
||||||
|
import babel from '@rollup/plugin-babel';
|
||||||
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
|
import flowRemoveTypes from 'flow-remove-types';
|
||||||
|
import json from '@rollup/plugin-json';
|
||||||
|
import multi from '@rollup/plugin-multi-entry';
|
||||||
|
import nodeResolve from '@rollup/plugin-node-resolve';
|
||||||
|
import nodePolyfills from 'rollup-plugin-node-polyfills';
|
||||||
|
import replace from '@rollup/plugin-replace';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
input: {
|
||||||
|
// include: [
|
||||||
|
// 'test/account.test.js',
|
||||||
|
// 'test/cluster.test.js',
|
||||||
|
// 'test/stake-program.test.js',
|
||||||
|
// ],
|
||||||
|
include: ['test/**/*.test.js'],
|
||||||
|
exclude: ['test/agent-manager.test.js', 'test/bpf-loader.test.js'],
|
||||||
|
},
|
||||||
|
external: ['node-forge', 'http2', '_stream_wrap'],
|
||||||
|
output: {
|
||||||
|
file: 'test/dist/bundle.js',
|
||||||
|
format: 'es',
|
||||||
|
sourcemap: true,
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
flow(),
|
||||||
|
multi(),
|
||||||
|
commonjs(),
|
||||||
|
nodeResolve({
|
||||||
|
browser: true,
|
||||||
|
preferBuiltins: false,
|
||||||
|
dedupe: ['bn.js', 'buffer'],
|
||||||
|
}),
|
||||||
|
babel({
|
||||||
|
exclude: '**/node_modules/**',
|
||||||
|
babelHelpers: 'runtime',
|
||||||
|
plugins: ['@babel/plugin-transform-runtime'],
|
||||||
|
}),
|
||||||
|
nodePolyfills(),
|
||||||
|
replace({
|
||||||
|
'process.env.BROWSER': 'true',
|
||||||
|
'process.env.TEST_LIVE': 'true',
|
||||||
|
}),
|
||||||
|
alias({
|
||||||
|
entries: [
|
||||||
|
{
|
||||||
|
find: /^\.\.\/src\/.*\.js$/,
|
||||||
|
replacement: './lib/index.browser.esm.js',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
json(),
|
||||||
|
],
|
||||||
|
onwarn: function (warning, rollupWarn) {
|
||||||
|
if (warning.code !== 'CIRCULAR_DEPENDENCY' && warning.code !== 'EVAL') {
|
||||||
|
rollupWarn(warning);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
treeshake: {
|
||||||
|
moduleSideEffects: path => path.endsWith('test.js'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Using this instead of rollup-plugin-flow due to
|
||||||
|
// https://github.com/leebyron/rollup-plugin-flow/issues/5
|
||||||
|
function flow() {
|
||||||
|
return {
|
||||||
|
name: 'flow-remove-types',
|
||||||
|
transform: code => ({
|
||||||
|
code: flowRemoveTypes(code).toString(),
|
||||||
|
map: null,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
@ -1,88 +1,82 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import {keccak_256} from 'js-sha3';
|
import {Buffer} from 'buffer';
|
||||||
import secp256k1 from 'secp256k1';
|
import createKeccakHash from 'keccak';
|
||||||
import {randomBytes} from 'crypto';
|
import {privateKeyVerify, ecdsaSign, publicKeyCreate} from 'secp256k1';
|
||||||
|
|
||||||
import {Secp256k1Program} from '../src/secp256k1-program';
|
|
||||||
import {mockRpcEnabled} from './__mocks__/node-fetch';
|
|
||||||
import {url} from './url';
|
|
||||||
import {
|
import {
|
||||||
Connection,
|
Connection,
|
||||||
Account,
|
Account,
|
||||||
sendAndConfirmTransaction,
|
sendAndConfirmTransaction,
|
||||||
LAMPORTS_PER_SOL,
|
LAMPORTS_PER_SOL,
|
||||||
Transaction,
|
Transaction,
|
||||||
|
Secp256k1Program,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
|
import {url} from './url';
|
||||||
|
import {helpers} from './mocks/rpc-http';
|
||||||
|
|
||||||
const {privateKeyVerify, ecdsaSign, publicKeyCreate} = secp256k1;
|
const randomPrivateKey = () => {
|
||||||
|
|
||||||
if (!mockRpcEnabled) {
|
|
||||||
jest.setTimeout(20000);
|
|
||||||
}
|
|
||||||
|
|
||||||
test('live create secp256k1 instruction with public key', async () => {
|
|
||||||
if (mockRpcEnabled) {
|
|
||||||
console.log('non-live test skipped');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const message = Buffer.from('This is a message');
|
|
||||||
|
|
||||||
let privateKey;
|
let privateKey;
|
||||||
do {
|
do {
|
||||||
privateKey = randomBytes(32);
|
privateKey = new Account().secretKey.slice(0, 32);
|
||||||
} while (!privateKeyVerify(privateKey));
|
} while (!privateKeyVerify(privateKey));
|
||||||
|
return privateKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (process.env.TEST_LIVE) {
|
||||||
|
describe('secp256k1', () => {
|
||||||
|
it('create secp256k1 instruction with public key', async () => {
|
||||||
|
const privateKey = randomPrivateKey();
|
||||||
const publicKey = publicKeyCreate(privateKey, false);
|
const publicKey = publicKeyCreate(privateKey, false);
|
||||||
const messageHash = Buffer.from(keccak_256.update(message).digest());
|
const message = Buffer.from('This is a message');
|
||||||
|
const messageHash = createKeccakHash('keccak256')
|
||||||
|
.update(message)
|
||||||
|
.digest();
|
||||||
const {signature, recid: recoveryId} = ecdsaSign(messageHash, privateKey);
|
const {signature, recid: recoveryId} = ecdsaSign(messageHash, privateKey);
|
||||||
|
const connection = new Connection(url, 'singleGossip');
|
||||||
|
|
||||||
const instruction = Secp256k1Program.createInstructionWithPublicKey({
|
const from = new Account();
|
||||||
|
await connection.confirmTransaction(
|
||||||
|
await connection.requestAirdrop(from.publicKey, 2 * LAMPORTS_PER_SOL),
|
||||||
|
'singleGossip',
|
||||||
|
);
|
||||||
|
|
||||||
|
const transaction = new Transaction().add(
|
||||||
|
Secp256k1Program.createInstructionWithPublicKey({
|
||||||
publicKey,
|
publicKey,
|
||||||
message,
|
message,
|
||||||
signature,
|
signature,
|
||||||
recoveryId,
|
recoveryId,
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
const transaction = new Transaction();
|
|
||||||
transaction.add(instruction);
|
|
||||||
|
|
||||||
const connection = new Connection(url, 'recent');
|
|
||||||
const from = new Account();
|
|
||||||
await connection.requestAirdrop(from.publicKey, 2 * LAMPORTS_PER_SOL);
|
|
||||||
|
|
||||||
await sendAndConfirmTransaction(connection, transaction, [from], {
|
await sendAndConfirmTransaction(connection, transaction, [from], {
|
||||||
commitment: 'single',
|
commitment: 'singleGossip',
|
||||||
skipPreflight: true,
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('live create secp256k1 instruction with private key', async () => {
|
it('create secp256k1 instruction with private key', async () => {
|
||||||
if (mockRpcEnabled) {
|
const privateKey = randomPrivateKey();
|
||||||
console.log('non-live test skipped');
|
const connection = new Connection(url, 'singleGossip');
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let privateKey;
|
const from = new Account();
|
||||||
do {
|
await connection.confirmTransaction(
|
||||||
privateKey = randomBytes(32);
|
await connection.requestAirdrop(from.publicKey, 2 * LAMPORTS_PER_SOL),
|
||||||
} while (!privateKeyVerify(privateKey));
|
'singleGossip',
|
||||||
|
);
|
||||||
|
|
||||||
const instruction = Secp256k1Program.createInstructionWithPrivateKey({
|
const transaction = new Transaction().add(
|
||||||
|
Secp256k1Program.createInstructionWithPrivateKey({
|
||||||
privateKey,
|
privateKey,
|
||||||
message: Buffer.from('Test 123'),
|
message: Buffer.from('Test 123'),
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
const transaction = new Transaction();
|
|
||||||
transaction.add(instruction);
|
|
||||||
|
|
||||||
const connection = new Connection(url, 'recent');
|
|
||||||
const from = new Account();
|
|
||||||
await connection.requestAirdrop(from.publicKey, 2 * LAMPORTS_PER_SOL);
|
|
||||||
|
|
||||||
await sendAndConfirmTransaction(connection, transaction, [from], {
|
await sendAndConfirmTransaction(connection, transaction, [from], {
|
||||||
commitment: 'single',
|
commitment: 'singleGossip',
|
||||||
skipPreflight: true,
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -1,13 +1,27 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import {expect} from 'chai';
|
||||||
import {decodeLength, encodeLength} from '../src/util/shortvec-encoding';
|
import {decodeLength, encodeLength} from '../src/util/shortvec-encoding';
|
||||||
|
|
||||||
function checkDecodedArray(array: Array<number>, expectedValue: number) {
|
function checkDecodedArray(array: Array<number>, expectedValue: number) {
|
||||||
expect(decodeLength(array)).toEqual(expectedValue);
|
expect(decodeLength(array)).to.eq(expectedValue);
|
||||||
expect(array.length).toEqual(0);
|
expect(array).to.have.length(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
test('shortvec decodeLength', () => {
|
function checkEncodedArray(
|
||||||
|
array: Array<number>,
|
||||||
|
len: number,
|
||||||
|
prevLength: number,
|
||||||
|
addedLength: number,
|
||||||
|
expectedArray: Array<number>,
|
||||||
|
) {
|
||||||
|
encodeLength(array, len);
|
||||||
|
expect(array).to.have.length(prevLength);
|
||||||
|
expect(array.slice(-addedLength)).to.eql(expectedArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('shortvec', () => {
|
||||||
|
it('decodeLength', () => {
|
||||||
let array = [];
|
let array = [];
|
||||||
checkDecodedArray(array, 0);
|
checkDecodedArray(array, 0);
|
||||||
|
|
||||||
@ -33,19 +47,7 @@ test('shortvec decodeLength', () => {
|
|||||||
checkDecodedArray(array, 0x200000);
|
checkDecodedArray(array, 0x200000);
|
||||||
});
|
});
|
||||||
|
|
||||||
function checkEncodedArray(
|
it('encodeLength', () => {
|
||||||
array: Array<number>,
|
|
||||||
len: number,
|
|
||||||
prevLength: number,
|
|
||||||
addedLength: number,
|
|
||||||
expectedArray: Array<number>,
|
|
||||||
) {
|
|
||||||
encodeLength(array, len);
|
|
||||||
expect(array.length).toEqual(prevLength);
|
|
||||||
expect(array.slice(-addedLength)).toEqual(expectedArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
test('shortvec encodeLength', () => {
|
|
||||||
let array = [];
|
let array = [];
|
||||||
let prevLength = 1;
|
let prevLength = 1;
|
||||||
checkEncodedArray(array, 0, prevLength, 1, [0]);
|
checkEncodedArray(array, 0, prevLength, 1, [0]);
|
||||||
@ -69,3 +71,4 @@ test('shortvec encodeLength', () => {
|
|||||||
0x01,
|
0x01,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import {expect, use} from 'chai';
|
||||||
|
import chaiAsPromised from 'chai-as-promised';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Account,
|
Account,
|
||||||
Authorized,
|
Authorized,
|
||||||
@ -14,16 +17,13 @@ import {
|
|||||||
SystemInstruction,
|
SystemInstruction,
|
||||||
Transaction,
|
Transaction,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
import {mockRpcEnabled} from './__mocks__/node-fetch';
|
import {helpers} from './mocks/rpc-http';
|
||||||
import {newAccountWithLamports} from './new-account-with-lamports';
|
|
||||||
import {url} from './url';
|
import {url} from './url';
|
||||||
|
|
||||||
if (!mockRpcEnabled) {
|
use(chaiAsPromised);
|
||||||
// Testing max commitment level takes around 20s to complete
|
|
||||||
jest.setTimeout(60000);
|
|
||||||
}
|
|
||||||
|
|
||||||
test('createAccountWithSeed', async () => {
|
describe('StakeProgram', () => {
|
||||||
|
it('createAccountWithSeed', async () => {
|
||||||
const fromPubkey = new Account().publicKey;
|
const fromPubkey = new Account().publicKey;
|
||||||
const seed = 'test string';
|
const seed = 'test string';
|
||||||
const newAccountPubkey = await PublicKey.createWithSeed(
|
const newAccountPubkey = await PublicKey.createWithSeed(
|
||||||
@ -44,7 +44,7 @@ test('createAccountWithSeed', async () => {
|
|||||||
lockup,
|
lockup,
|
||||||
lamports,
|
lamports,
|
||||||
});
|
});
|
||||||
expect(transaction.instructions).toHaveLength(2);
|
expect(transaction.instructions).to.have.length(2);
|
||||||
const [systemInstruction, stakeInstruction] = transaction.instructions;
|
const [systemInstruction, stakeInstruction] = transaction.instructions;
|
||||||
const systemParams = {
|
const systemParams = {
|
||||||
fromPubkey,
|
fromPubkey,
|
||||||
@ -55,16 +55,16 @@ test('createAccountWithSeed', async () => {
|
|||||||
space: StakeProgram.space,
|
space: StakeProgram.space,
|
||||||
programId: StakeProgram.programId,
|
programId: StakeProgram.programId,
|
||||||
};
|
};
|
||||||
expect(systemParams).toEqual(
|
expect(systemParams).to.eql(
|
||||||
SystemInstruction.decodeCreateWithSeed(systemInstruction),
|
SystemInstruction.decodeCreateWithSeed(systemInstruction),
|
||||||
);
|
);
|
||||||
const initParams = {stakePubkey: newAccountPubkey, authorized, lockup};
|
const initParams = {stakePubkey: newAccountPubkey, authorized, lockup};
|
||||||
expect(initParams).toEqual(
|
expect(initParams).to.eql(
|
||||||
StakeInstruction.decodeInitialize(stakeInstruction),
|
StakeInstruction.decodeInitialize(stakeInstruction),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('createAccount', () => {
|
it('createAccount', () => {
|
||||||
const fromPubkey = new Account().publicKey;
|
const fromPubkey = new Account().publicKey;
|
||||||
const newAccountPubkey = new Account().publicKey;
|
const newAccountPubkey = new Account().publicKey;
|
||||||
const authorizedPubkey = new Account().publicKey;
|
const authorizedPubkey = new Account().publicKey;
|
||||||
@ -78,7 +78,7 @@ test('createAccount', () => {
|
|||||||
lockup,
|
lockup,
|
||||||
lamports,
|
lamports,
|
||||||
});
|
});
|
||||||
expect(transaction.instructions).toHaveLength(2);
|
expect(transaction.instructions).to.have.length(2);
|
||||||
const [systemInstruction, stakeInstruction] = transaction.instructions;
|
const [systemInstruction, stakeInstruction] = transaction.instructions;
|
||||||
const systemParams = {
|
const systemParams = {
|
||||||
fromPubkey,
|
fromPubkey,
|
||||||
@ -87,17 +87,17 @@ test('createAccount', () => {
|
|||||||
space: StakeProgram.space,
|
space: StakeProgram.space,
|
||||||
programId: StakeProgram.programId,
|
programId: StakeProgram.programId,
|
||||||
};
|
};
|
||||||
expect(systemParams).toEqual(
|
expect(systemParams).to.eql(
|
||||||
SystemInstruction.decodeCreateAccount(systemInstruction),
|
SystemInstruction.decodeCreateAccount(systemInstruction),
|
||||||
);
|
);
|
||||||
|
|
||||||
const initParams = {stakePubkey: newAccountPubkey, authorized, lockup};
|
const initParams = {stakePubkey: newAccountPubkey, authorized, lockup};
|
||||||
expect(initParams).toEqual(
|
expect(initParams).to.eql(
|
||||||
StakeInstruction.decodeInitialize(stakeInstruction),
|
StakeInstruction.decodeInitialize(stakeInstruction),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('delegate', () => {
|
it('delegate', () => {
|
||||||
const stakePubkey = new Account().publicKey;
|
const stakePubkey = new Account().publicKey;
|
||||||
const authorizedPubkey = new Account().publicKey;
|
const authorizedPubkey = new Account().publicKey;
|
||||||
const votePubkey = new Account().publicKey;
|
const votePubkey = new Account().publicKey;
|
||||||
@ -107,12 +107,12 @@ test('delegate', () => {
|
|||||||
votePubkey,
|
votePubkey,
|
||||||
};
|
};
|
||||||
const transaction = StakeProgram.delegate(params);
|
const transaction = StakeProgram.delegate(params);
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [stakeInstruction] = transaction.instructions;
|
const [stakeInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(StakeInstruction.decodeDelegate(stakeInstruction));
|
expect(params).to.eql(StakeInstruction.decodeDelegate(stakeInstruction));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('authorize', () => {
|
it('authorize', () => {
|
||||||
const stakePubkey = new Account().publicKey;
|
const stakePubkey = new Account().publicKey;
|
||||||
const authorizedPubkey = new Account().publicKey;
|
const authorizedPubkey = new Account().publicKey;
|
||||||
const newAuthorizedPubkey = new Account().publicKey;
|
const newAuthorizedPubkey = new Account().publicKey;
|
||||||
@ -124,12 +124,12 @@ test('authorize', () => {
|
|||||||
stakeAuthorizationType,
|
stakeAuthorizationType,
|
||||||
};
|
};
|
||||||
const transaction = StakeProgram.authorize(params);
|
const transaction = StakeProgram.authorize(params);
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [stakeInstruction] = transaction.instructions;
|
const [stakeInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(StakeInstruction.decodeAuthorize(stakeInstruction));
|
expect(params).to.eql(StakeInstruction.decodeAuthorize(stakeInstruction));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('authorize with custodian', () => {
|
it('authorize with custodian', () => {
|
||||||
const stakePubkey = new Account().publicKey;
|
const stakePubkey = new Account().publicKey;
|
||||||
const authorizedPubkey = new Account().publicKey;
|
const authorizedPubkey = new Account().publicKey;
|
||||||
const newAuthorizedPubkey = new Account().publicKey;
|
const newAuthorizedPubkey = new Account().publicKey;
|
||||||
@ -143,12 +143,12 @@ test('authorize with custodian', () => {
|
|||||||
custodianPubkey,
|
custodianPubkey,
|
||||||
};
|
};
|
||||||
const transaction = StakeProgram.authorize(params);
|
const transaction = StakeProgram.authorize(params);
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [stakeInstruction] = transaction.instructions;
|
const [stakeInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(StakeInstruction.decodeAuthorize(stakeInstruction));
|
expect(params).to.eql(StakeInstruction.decodeAuthorize(stakeInstruction));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('authorizeWithSeed', () => {
|
it('authorizeWithSeed', () => {
|
||||||
const stakePubkey = new Account().publicKey;
|
const stakePubkey = new Account().publicKey;
|
||||||
const authorityBase = new Account().publicKey;
|
const authorityBase = new Account().publicKey;
|
||||||
const authoritySeed = 'test string';
|
const authoritySeed = 'test string';
|
||||||
@ -164,14 +164,14 @@ test('authorizeWithSeed', () => {
|
|||||||
stakeAuthorizationType,
|
stakeAuthorizationType,
|
||||||
};
|
};
|
||||||
const transaction = StakeProgram.authorizeWithSeed(params);
|
const transaction = StakeProgram.authorizeWithSeed(params);
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [stakeInstruction] = transaction.instructions;
|
const [stakeInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(
|
expect(params).to.eql(
|
||||||
StakeInstruction.decodeAuthorizeWithSeed(stakeInstruction),
|
StakeInstruction.decodeAuthorizeWithSeed(stakeInstruction),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('authorizeWithSeed with custodian', () => {
|
it('authorizeWithSeed with custodian', () => {
|
||||||
const stakePubkey = new Account().publicKey;
|
const stakePubkey = new Account().publicKey;
|
||||||
const authorityBase = new Account().publicKey;
|
const authorityBase = new Account().publicKey;
|
||||||
const authoritySeed = 'test string';
|
const authoritySeed = 'test string';
|
||||||
@ -189,14 +189,14 @@ test('authorizeWithSeed with custodian', () => {
|
|||||||
custodianPubkey,
|
custodianPubkey,
|
||||||
};
|
};
|
||||||
const transaction = StakeProgram.authorizeWithSeed(params);
|
const transaction = StakeProgram.authorizeWithSeed(params);
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [stakeInstruction] = transaction.instructions;
|
const [stakeInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(
|
expect(params).to.eql(
|
||||||
StakeInstruction.decodeAuthorizeWithSeed(stakeInstruction),
|
StakeInstruction.decodeAuthorizeWithSeed(stakeInstruction),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('split', () => {
|
it('split', () => {
|
||||||
const stakePubkey = new Account().publicKey;
|
const stakePubkey = new Account().publicKey;
|
||||||
const authorizedPubkey = new Account().publicKey;
|
const authorizedPubkey = new Account().publicKey;
|
||||||
const splitStakePubkey = new Account().publicKey;
|
const splitStakePubkey = new Account().publicKey;
|
||||||
@ -207,7 +207,7 @@ test('split', () => {
|
|||||||
lamports: 123,
|
lamports: 123,
|
||||||
};
|
};
|
||||||
const transaction = StakeProgram.split(params);
|
const transaction = StakeProgram.split(params);
|
||||||
expect(transaction.instructions).toHaveLength(2);
|
expect(transaction.instructions).to.have.length(2);
|
||||||
const [systemInstruction, stakeInstruction] = transaction.instructions;
|
const [systemInstruction, stakeInstruction] = transaction.instructions;
|
||||||
const systemParams = {
|
const systemParams = {
|
||||||
fromPubkey: authorizedPubkey,
|
fromPubkey: authorizedPubkey,
|
||||||
@ -216,13 +216,13 @@ test('split', () => {
|
|||||||
space: StakeProgram.space,
|
space: StakeProgram.space,
|
||||||
programId: StakeProgram.programId,
|
programId: StakeProgram.programId,
|
||||||
};
|
};
|
||||||
expect(systemParams).toEqual(
|
expect(systemParams).to.eql(
|
||||||
SystemInstruction.decodeCreateAccount(systemInstruction),
|
SystemInstruction.decodeCreateAccount(systemInstruction),
|
||||||
);
|
);
|
||||||
expect(params).toEqual(StakeInstruction.decodeSplit(stakeInstruction));
|
expect(params).to.eql(StakeInstruction.decodeSplit(stakeInstruction));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('withdraw', () => {
|
it('withdraw', () => {
|
||||||
const stakePubkey = new Account().publicKey;
|
const stakePubkey = new Account().publicKey;
|
||||||
const authorizedPubkey = new Account().publicKey;
|
const authorizedPubkey = new Account().publicKey;
|
||||||
const toPubkey = new Account().publicKey;
|
const toPubkey = new Account().publicKey;
|
||||||
@ -233,12 +233,12 @@ test('withdraw', () => {
|
|||||||
lamports: 123,
|
lamports: 123,
|
||||||
};
|
};
|
||||||
const transaction = StakeProgram.withdraw(params);
|
const transaction = StakeProgram.withdraw(params);
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [stakeInstruction] = transaction.instructions;
|
const [stakeInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(StakeInstruction.decodeWithdraw(stakeInstruction));
|
expect(params).to.eql(StakeInstruction.decodeWithdraw(stakeInstruction));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('withdraw with custodian', () => {
|
it('withdraw with custodian', () => {
|
||||||
const stakePubkey = new Account().publicKey;
|
const stakePubkey = new Account().publicKey;
|
||||||
const authorizedPubkey = new Account().publicKey;
|
const authorizedPubkey = new Account().publicKey;
|
||||||
const toPubkey = new Account().publicKey;
|
const toPubkey = new Account().publicKey;
|
||||||
@ -251,22 +251,22 @@ test('withdraw with custodian', () => {
|
|||||||
custodianPubkey,
|
custodianPubkey,
|
||||||
};
|
};
|
||||||
const transaction = StakeProgram.withdraw(params);
|
const transaction = StakeProgram.withdraw(params);
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [stakeInstruction] = transaction.instructions;
|
const [stakeInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(StakeInstruction.decodeWithdraw(stakeInstruction));
|
expect(params).to.eql(StakeInstruction.decodeWithdraw(stakeInstruction));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('deactivate', () => {
|
it('deactivate', () => {
|
||||||
const stakePubkey = new Account().publicKey;
|
const stakePubkey = new Account().publicKey;
|
||||||
const authorizedPubkey = new Account().publicKey;
|
const authorizedPubkey = new Account().publicKey;
|
||||||
const params = {stakePubkey, authorizedPubkey};
|
const params = {stakePubkey, authorizedPubkey};
|
||||||
const transaction = StakeProgram.deactivate(params);
|
const transaction = StakeProgram.deactivate(params);
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [stakeInstruction] = transaction.instructions;
|
const [stakeInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(StakeInstruction.decodeDeactivate(stakeInstruction));
|
expect(params).to.eql(StakeInstruction.decodeDeactivate(stakeInstruction));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('StakeInstructions', async () => {
|
it('StakeInstructions', async () => {
|
||||||
const from = new Account();
|
const from = new Account();
|
||||||
const seed = 'test string';
|
const seed = 'test string';
|
||||||
const newAccountPubkey = await PublicKey.createWithSeed(
|
const newAccountPubkey = await PublicKey.createWithSeed(
|
||||||
@ -290,22 +290,22 @@ test('StakeInstructions', async () => {
|
|||||||
createWithSeed,
|
createWithSeed,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(createWithSeedTransaction.instructions).toHaveLength(2);
|
expect(createWithSeedTransaction.instructions).to.have.length(2);
|
||||||
const systemInstructionType = SystemInstruction.decodeInstructionType(
|
const systemInstructionType = SystemInstruction.decodeInstructionType(
|
||||||
createWithSeedTransaction.instructions[0],
|
createWithSeedTransaction.instructions[0],
|
||||||
);
|
);
|
||||||
expect(systemInstructionType).toEqual('CreateWithSeed');
|
expect(systemInstructionType).to.eq('CreateWithSeed');
|
||||||
|
|
||||||
const stakeInstructionType = StakeInstruction.decodeInstructionType(
|
const stakeInstructionType = StakeInstruction.decodeInstructionType(
|
||||||
createWithSeedTransaction.instructions[1],
|
createWithSeedTransaction.instructions[1],
|
||||||
);
|
);
|
||||||
expect(stakeInstructionType).toEqual('Initialize');
|
expect(stakeInstructionType).to.eq('Initialize');
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
StakeInstruction.decodeInstructionType(
|
StakeInstruction.decodeInstructionType(
|
||||||
createWithSeedTransaction.instructions[0],
|
createWithSeedTransaction.instructions[0],
|
||||||
);
|
);
|
||||||
}).toThrow();
|
}).to.throw();
|
||||||
|
|
||||||
const stake = new Account();
|
const stake = new Account();
|
||||||
const vote = new Account();
|
const vote = new Account();
|
||||||
@ -315,38 +315,47 @@ test('StakeInstructions', async () => {
|
|||||||
votePubkey: vote.publicKey,
|
votePubkey: vote.publicKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
const delegateTransaction = new Transaction({recentBlockhash}).add(delegate);
|
const delegateTransaction = new Transaction({recentBlockhash}).add(
|
||||||
|
delegate,
|
||||||
|
);
|
||||||
const anotherStakeInstructionType = StakeInstruction.decodeInstructionType(
|
const anotherStakeInstructionType = StakeInstruction.decodeInstructionType(
|
||||||
delegateTransaction.instructions[0],
|
delegateTransaction.instructions[0],
|
||||||
);
|
);
|
||||||
expect(anotherStakeInstructionType).toEqual('Delegate');
|
expect(anotherStakeInstructionType).to.eq('Delegate');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('live staking actions', async () => {
|
if (process.env.TEST_LIVE) {
|
||||||
if (mockRpcEnabled) {
|
it('live staking actions', async () => {
|
||||||
console.log('non-live test skipped');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const connection = new Connection(url, 'singleGossip');
|
const connection = new Connection(url, 'singleGossip');
|
||||||
|
|
||||||
const voteAccounts = await connection.getVoteAccounts();
|
const voteAccounts = await connection.getVoteAccounts();
|
||||||
const voteAccount = voteAccounts.current.concat(voteAccounts.delinquent)[0];
|
const voteAccount = voteAccounts.current.concat(
|
||||||
|
voteAccounts.delinquent,
|
||||||
|
)[0];
|
||||||
const votePubkey = new PublicKey(voteAccount.votePubkey);
|
const votePubkey = new PublicKey(voteAccount.votePubkey);
|
||||||
|
|
||||||
const from = await newAccountWithLamports(connection, 2 * LAMPORTS_PER_SOL);
|
const payer = new Account();
|
||||||
const authorized = await newAccountWithLamports(
|
await helpers.airdrop({
|
||||||
connection,
|
connection,
|
||||||
2 * LAMPORTS_PER_SOL,
|
address: payer.publicKey,
|
||||||
);
|
amount: 2 * LAMPORTS_PER_SOL,
|
||||||
|
});
|
||||||
|
|
||||||
|
const authorized = new Account();
|
||||||
|
await helpers.airdrop({
|
||||||
|
connection,
|
||||||
|
address: authorized.publicKey,
|
||||||
|
amount: 2 * LAMPORTS_PER_SOL,
|
||||||
|
});
|
||||||
|
|
||||||
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
||||||
StakeProgram.space,
|
StakeProgram.space,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(await connection.getBalance(from.publicKey)).toEqual(
|
expect(await connection.getBalance(payer.publicKey)).to.eq(
|
||||||
2 * LAMPORTS_PER_SOL,
|
2 * LAMPORTS_PER_SOL,
|
||||||
);
|
);
|
||||||
expect(await connection.getBalance(authorized.publicKey)).toEqual(
|
expect(await connection.getBalance(authorized.publicKey)).to.eq(
|
||||||
2 * LAMPORTS_PER_SOL,
|
2 * LAMPORTS_PER_SOL,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -354,9 +363,12 @@ test('live staking actions', async () => {
|
|||||||
// Create Stake account without seed
|
// Create Stake account without seed
|
||||||
const newStakeAccount = new Account();
|
const newStakeAccount = new Account();
|
||||||
let createAndInitialize = StakeProgram.createAccount({
|
let createAndInitialize = StakeProgram.createAccount({
|
||||||
fromPubkey: from.publicKey,
|
fromPubkey: payer.publicKey,
|
||||||
stakePubkey: newStakeAccount.publicKey,
|
stakePubkey: newStakeAccount.publicKey,
|
||||||
authorized: new Authorized(authorized.publicKey, authorized.publicKey),
|
authorized: new Authorized(
|
||||||
|
authorized.publicKey,
|
||||||
|
authorized.publicKey,
|
||||||
|
),
|
||||||
lockup: new Lockup(0, 0, new PublicKey(0)),
|
lockup: new Lockup(0, 0, new PublicKey(0)),
|
||||||
lamports: minimumAmount + 42,
|
lamports: minimumAmount + 42,
|
||||||
});
|
});
|
||||||
@ -364,14 +376,14 @@ test('live staking actions', async () => {
|
|||||||
await sendAndConfirmTransaction(
|
await sendAndConfirmTransaction(
|
||||||
connection,
|
connection,
|
||||||
createAndInitialize,
|
createAndInitialize,
|
||||||
[from, newStakeAccount],
|
[payer, newStakeAccount],
|
||||||
{commitment: 'singleGossip'},
|
{preflightCommitment: 'singleGossip'},
|
||||||
);
|
);
|
||||||
expect(await connection.getBalance(newStakeAccount.publicKey)).toEqual(
|
expect(await connection.getBalance(newStakeAccount.publicKey)).to.eq(
|
||||||
minimumAmount + 42,
|
minimumAmount + 42,
|
||||||
);
|
);
|
||||||
|
|
||||||
let delegation = StakeProgram.delegate({
|
const delegation = StakeProgram.delegate({
|
||||||
stakePubkey: newStakeAccount.publicKey,
|
stakePubkey: newStakeAccount.publicKey,
|
||||||
authorizedPubkey: authorized.publicKey,
|
authorizedPubkey: authorized.publicKey,
|
||||||
votePubkey,
|
votePubkey,
|
||||||
@ -384,15 +396,15 @@ test('live staking actions', async () => {
|
|||||||
// Create Stake account with seed
|
// Create Stake account with seed
|
||||||
const seed = 'test string';
|
const seed = 'test string';
|
||||||
const newAccountPubkey = await PublicKey.createWithSeed(
|
const newAccountPubkey = await PublicKey.createWithSeed(
|
||||||
from.publicKey,
|
payer.publicKey,
|
||||||
seed,
|
seed,
|
||||||
StakeProgram.programId,
|
StakeProgram.programId,
|
||||||
);
|
);
|
||||||
|
|
||||||
let createAndInitializeWithSeed = StakeProgram.createAccountWithSeed({
|
let createAndInitializeWithSeed = StakeProgram.createAccountWithSeed({
|
||||||
fromPubkey: from.publicKey,
|
fromPubkey: payer.publicKey,
|
||||||
stakePubkey: newAccountPubkey,
|
stakePubkey: newAccountPubkey,
|
||||||
basePubkey: from.publicKey,
|
basePubkey: payer.publicKey,
|
||||||
seed,
|
seed,
|
||||||
authorized: new Authorized(authorized.publicKey, authorized.publicKey),
|
authorized: new Authorized(authorized.publicKey, authorized.publicKey),
|
||||||
lockup: new Lockup(0, 0, new PublicKey(0)),
|
lockup: new Lockup(0, 0, new PublicKey(0)),
|
||||||
@ -402,11 +414,11 @@ test('live staking actions', async () => {
|
|||||||
await sendAndConfirmTransaction(
|
await sendAndConfirmTransaction(
|
||||||
connection,
|
connection,
|
||||||
createAndInitializeWithSeed,
|
createAndInitializeWithSeed,
|
||||||
[from],
|
[payer],
|
||||||
{commitment: 'singleGossip'},
|
{preflightCommitment: 'singleGossip'},
|
||||||
);
|
);
|
||||||
let originalStakeBalance = await connection.getBalance(newAccountPubkey);
|
let originalStakeBalance = await connection.getBalance(newAccountPubkey);
|
||||||
expect(originalStakeBalance).toEqual(3 * minimumAmount + 42);
|
expect(originalStakeBalance).to.eq(3 * minimumAmount + 42);
|
||||||
|
|
||||||
let delegation = StakeProgram.delegate({
|
let delegation = StakeProgram.delegate({
|
||||||
stakePubkey: newAccountPubkey,
|
stakePubkey: newAccountPubkey,
|
||||||
@ -414,7 +426,7 @@ test('live staking actions', async () => {
|
|||||||
votePubkey,
|
votePubkey,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(connection, delegation, [authorized], {
|
await sendAndConfirmTransaction(connection, delegation, [authorized], {
|
||||||
commitment: 'singleGossip',
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test that withdraw fails before deactivation
|
// Test that withdraw fails before deactivation
|
||||||
@ -427,9 +439,9 @@ test('live staking actions', async () => {
|
|||||||
});
|
});
|
||||||
await expect(
|
await expect(
|
||||||
sendAndConfirmTransaction(connection, withdraw, [authorized], {
|
sendAndConfirmTransaction(connection, withdraw, [authorized], {
|
||||||
commitment: 'singleGossip',
|
preflightCommitment: 'singleGossip',
|
||||||
}),
|
}),
|
||||||
).rejects.toThrow();
|
).to.be.rejected;
|
||||||
|
|
||||||
// Deactivate stake
|
// Deactivate stake
|
||||||
let deactivate = StakeProgram.deactivate({
|
let deactivate = StakeProgram.deactivate({
|
||||||
@ -437,7 +449,7 @@ test('live staking actions', async () => {
|
|||||||
authorizedPubkey: authorized.publicKey,
|
authorizedPubkey: authorized.publicKey,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(connection, deactivate, [authorized], {
|
await sendAndConfirmTransaction(connection, deactivate, [authorized], {
|
||||||
commitment: 'singleGossip',
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
});
|
||||||
|
|
||||||
let stakeActivationState;
|
let stakeActivationState;
|
||||||
@ -456,10 +468,10 @@ test('live staking actions', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await sendAndConfirmTransaction(connection, withdraw, [authorized], {
|
await sendAndConfirmTransaction(connection, withdraw, [authorized], {
|
||||||
commitment: 'singleGossip',
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
});
|
||||||
const recipientBalance = await connection.getBalance(recipient.publicKey);
|
const recipientBalance = await connection.getBalance(recipient.publicKey);
|
||||||
expect(recipientBalance).toEqual(minimumAmount + 20);
|
expect(recipientBalance).to.eq(minimumAmount + 20);
|
||||||
|
|
||||||
// Split stake
|
// Split stake
|
||||||
const newStake = new Account();
|
const newStake = new Account();
|
||||||
@ -469,15 +481,23 @@ test('live staking actions', async () => {
|
|||||||
splitStakePubkey: newStake.publicKey,
|
splitStakePubkey: newStake.publicKey,
|
||||||
lamports: minimumAmount + 20,
|
lamports: minimumAmount + 20,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(connection, split, [authorized, newStake], {
|
await sendAndConfirmTransaction(
|
||||||
commitment: 'singleGossip',
|
connection,
|
||||||
});
|
split,
|
||||||
|
[authorized, newStake],
|
||||||
|
{
|
||||||
|
preflightCommitment: 'singleGossip',
|
||||||
|
},
|
||||||
|
);
|
||||||
const balance = await connection.getBalance(newAccountPubkey);
|
const balance = await connection.getBalance(newAccountPubkey);
|
||||||
expect(balance).toEqual(minimumAmount + 2);
|
expect(balance).to.eq(minimumAmount + 2);
|
||||||
|
|
||||||
// Authorize to new account
|
// Authorize to new account
|
||||||
const newAuthorized = new Account();
|
const newAuthorized = new Account();
|
||||||
await connection.requestAirdrop(newAuthorized.publicKey, LAMPORTS_PER_SOL);
|
await connection.requestAirdrop(
|
||||||
|
newAuthorized.publicKey,
|
||||||
|
LAMPORTS_PER_SOL,
|
||||||
|
);
|
||||||
|
|
||||||
let authorize = StakeProgram.authorize({
|
let authorize = StakeProgram.authorize({
|
||||||
stakePubkey: newAccountPubkey,
|
stakePubkey: newAccountPubkey,
|
||||||
@ -486,7 +506,7 @@ test('live staking actions', async () => {
|
|||||||
stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer,
|
stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(connection, authorize, [authorized], {
|
await sendAndConfirmTransaction(connection, authorize, [authorized], {
|
||||||
commitment: 'singleGossip',
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
});
|
||||||
authorize = StakeProgram.authorize({
|
authorize = StakeProgram.authorize({
|
||||||
stakePubkey: newAccountPubkey,
|
stakePubkey: newAccountPubkey,
|
||||||
@ -495,7 +515,7 @@ test('live staking actions', async () => {
|
|||||||
stakeAuthorizationType: StakeAuthorizationLayout.Staker,
|
stakeAuthorizationType: StakeAuthorizationLayout.Staker,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(connection, authorize, [authorized], {
|
await sendAndConfirmTransaction(connection, authorize, [authorized], {
|
||||||
commitment: 'singleGossip',
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test old authorized can't delegate
|
// Test old authorized can't delegate
|
||||||
@ -505,10 +525,15 @@ test('live staking actions', async () => {
|
|||||||
votePubkey,
|
votePubkey,
|
||||||
});
|
});
|
||||||
await expect(
|
await expect(
|
||||||
sendAndConfirmTransaction(connection, delegateNotAuthorized, [authorized], {
|
sendAndConfirmTransaction(
|
||||||
commitment: 'singleGossip',
|
connection,
|
||||||
}),
|
delegateNotAuthorized,
|
||||||
).rejects.toThrow();
|
[authorized],
|
||||||
|
{
|
||||||
|
preflightCommitment: 'singleGossip',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).to.be.rejected;
|
||||||
|
|
||||||
// Authorize a derived address
|
// Authorize a derived address
|
||||||
authorize = StakeProgram.authorize({
|
authorize = StakeProgram.authorize({
|
||||||
@ -518,19 +543,21 @@ test('live staking actions', async () => {
|
|||||||
stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer,
|
stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(connection, authorize, [newAuthorized], {
|
await sendAndConfirmTransaction(connection, authorize, [newAuthorized], {
|
||||||
commitment: 'singleGossip',
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
});
|
||||||
|
|
||||||
// Restore the previous authority using a derived address
|
// Restore the previous authority using a derived address
|
||||||
authorize = StakeProgram.authorizeWithSeed({
|
authorize = StakeProgram.authorizeWithSeed({
|
||||||
stakePubkey: newAccountPubkey,
|
stakePubkey: newAccountPubkey,
|
||||||
authorityBase: from.publicKey,
|
authorityBase: payer.publicKey,
|
||||||
authoritySeed: seed,
|
authoritySeed: seed,
|
||||||
authorityOwner: StakeProgram.programId,
|
authorityOwner: StakeProgram.programId,
|
||||||
newAuthorizedPubkey: newAuthorized.publicKey,
|
newAuthorizedPubkey: newAuthorized.publicKey,
|
||||||
stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer,
|
stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer,
|
||||||
});
|
});
|
||||||
await sendAndConfirmTransaction(connection, authorize, [from], {
|
await sendAndConfirmTransaction(connection, authorize, [payer], {
|
||||||
commitment: 'singleGossip',
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
});
|
||||||
|
}).timeout(10 * 1000);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import {Buffer} from 'buffer';
|
||||||
|
import {expect} from 'chai';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Account,
|
Account,
|
||||||
Connection,
|
Connection,
|
||||||
@ -13,17 +16,12 @@ import {
|
|||||||
LAMPORTS_PER_SOL,
|
LAMPORTS_PER_SOL,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
import {NONCE_ACCOUNT_LENGTH} from '../src/nonce-account';
|
import {NONCE_ACCOUNT_LENGTH} from '../src/nonce-account';
|
||||||
import {mockRpcEnabled} from './__mocks__/node-fetch';
|
|
||||||
import {newAccountWithLamports} from './new-account-with-lamports';
|
|
||||||
import {sleep} from '../src/util/sleep';
|
import {sleep} from '../src/util/sleep';
|
||||||
|
import {helpers} from './mocks/rpc-http';
|
||||||
import {url} from './url';
|
import {url} from './url';
|
||||||
|
|
||||||
if (!mockRpcEnabled) {
|
describe('SystemProgram', () => {
|
||||||
// Testing max commitment level takes around 20s to complete
|
it('createAccount', () => {
|
||||||
jest.setTimeout(30000);
|
|
||||||
}
|
|
||||||
|
|
||||||
test('createAccount', () => {
|
|
||||||
const params = {
|
const params = {
|
||||||
fromPubkey: new Account().publicKey,
|
fromPubkey: new Account().publicKey,
|
||||||
newAccountPubkey: new Account().publicKey,
|
newAccountPubkey: new Account().publicKey,
|
||||||
@ -34,26 +32,26 @@ test('createAccount', () => {
|
|||||||
const transaction = new Transaction().add(
|
const transaction = new Transaction().add(
|
||||||
SystemProgram.createAccount(params),
|
SystemProgram.createAccount(params),
|
||||||
);
|
);
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [systemInstruction] = transaction.instructions;
|
const [systemInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(
|
expect(params).to.eql(
|
||||||
SystemInstruction.decodeCreateAccount(systemInstruction),
|
SystemInstruction.decodeCreateAccount(systemInstruction),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('transfer', () => {
|
it('transfer', () => {
|
||||||
const params = {
|
const params = {
|
||||||
fromPubkey: new Account().publicKey,
|
fromPubkey: new Account().publicKey,
|
||||||
toPubkey: new Account().publicKey,
|
toPubkey: new Account().publicKey,
|
||||||
lamports: 123,
|
lamports: 123,
|
||||||
};
|
};
|
||||||
const transaction = new Transaction().add(SystemProgram.transfer(params));
|
const transaction = new Transaction().add(SystemProgram.transfer(params));
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [systemInstruction] = transaction.instructions;
|
const [systemInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(SystemInstruction.decodeTransfer(systemInstruction));
|
expect(params).to.eql(SystemInstruction.decodeTransfer(systemInstruction));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('transferWithSeed', () => {
|
it('transferWithSeed', () => {
|
||||||
const params = {
|
const params = {
|
||||||
fromPubkey: new Account().publicKey,
|
fromPubkey: new Account().publicKey,
|
||||||
basePubkey: new Account().publicKey,
|
basePubkey: new Account().publicKey,
|
||||||
@ -63,25 +61,25 @@ test('transferWithSeed', () => {
|
|||||||
programId: new Account().publicKey,
|
programId: new Account().publicKey,
|
||||||
};
|
};
|
||||||
const transaction = new Transaction().add(SystemProgram.transfer(params));
|
const transaction = new Transaction().add(SystemProgram.transfer(params));
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [systemInstruction] = transaction.instructions;
|
const [systemInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(
|
expect(params).to.eql(
|
||||||
SystemInstruction.decodeTransferWithSeed(systemInstruction),
|
SystemInstruction.decodeTransferWithSeed(systemInstruction),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('allocate', () => {
|
it('allocate', () => {
|
||||||
const params = {
|
const params = {
|
||||||
accountPubkey: new Account().publicKey,
|
accountPubkey: new Account().publicKey,
|
||||||
space: 42,
|
space: 42,
|
||||||
};
|
};
|
||||||
const transaction = new Transaction().add(SystemProgram.allocate(params));
|
const transaction = new Transaction().add(SystemProgram.allocate(params));
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [systemInstruction] = transaction.instructions;
|
const [systemInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(SystemInstruction.decodeAllocate(systemInstruction));
|
expect(params).to.eql(SystemInstruction.decodeAllocate(systemInstruction));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('allocateWithSeed', () => {
|
it('allocateWithSeed', () => {
|
||||||
const params = {
|
const params = {
|
||||||
accountPubkey: new Account().publicKey,
|
accountPubkey: new Account().publicKey,
|
||||||
basePubkey: new Account().publicKey,
|
basePubkey: new Account().publicKey,
|
||||||
@ -90,25 +88,25 @@ test('allocateWithSeed', () => {
|
|||||||
programId: new Account().publicKey,
|
programId: new Account().publicKey,
|
||||||
};
|
};
|
||||||
const transaction = new Transaction().add(SystemProgram.allocate(params));
|
const transaction = new Transaction().add(SystemProgram.allocate(params));
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [systemInstruction] = transaction.instructions;
|
const [systemInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(
|
expect(params).to.eql(
|
||||||
SystemInstruction.decodeAllocateWithSeed(systemInstruction),
|
SystemInstruction.decodeAllocateWithSeed(systemInstruction),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('assign', () => {
|
it('assign', () => {
|
||||||
const params = {
|
const params = {
|
||||||
accountPubkey: new Account().publicKey,
|
accountPubkey: new Account().publicKey,
|
||||||
programId: new Account().publicKey,
|
programId: new Account().publicKey,
|
||||||
};
|
};
|
||||||
const transaction = new Transaction().add(SystemProgram.assign(params));
|
const transaction = new Transaction().add(SystemProgram.assign(params));
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [systemInstruction] = transaction.instructions;
|
const [systemInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(SystemInstruction.decodeAssign(systemInstruction));
|
expect(params).to.eql(SystemInstruction.decodeAssign(systemInstruction));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('assignWithSeed', () => {
|
it('assignWithSeed', () => {
|
||||||
const params = {
|
const params = {
|
||||||
accountPubkey: new Account().publicKey,
|
accountPubkey: new Account().publicKey,
|
||||||
basePubkey: new Account().publicKey,
|
basePubkey: new Account().publicKey,
|
||||||
@ -116,14 +114,14 @@ test('assignWithSeed', () => {
|
|||||||
programId: new Account().publicKey,
|
programId: new Account().publicKey,
|
||||||
};
|
};
|
||||||
const transaction = new Transaction().add(SystemProgram.assign(params));
|
const transaction = new Transaction().add(SystemProgram.assign(params));
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [systemInstruction] = transaction.instructions;
|
const [systemInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(
|
expect(params).to.eql(
|
||||||
SystemInstruction.decodeAssignWithSeed(systemInstruction),
|
SystemInstruction.decodeAssignWithSeed(systemInstruction),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('createAccountWithSeed', () => {
|
it('createAccountWithSeed', () => {
|
||||||
const fromPubkey = new Account().publicKey;
|
const fromPubkey = new Account().publicKey;
|
||||||
const params = {
|
const params = {
|
||||||
fromPubkey,
|
fromPubkey,
|
||||||
@ -137,14 +135,14 @@ test('createAccountWithSeed', () => {
|
|||||||
const transaction = new Transaction().add(
|
const transaction = new Transaction().add(
|
||||||
SystemProgram.createAccountWithSeed(params),
|
SystemProgram.createAccountWithSeed(params),
|
||||||
);
|
);
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [systemInstruction] = transaction.instructions;
|
const [systemInstruction] = transaction.instructions;
|
||||||
expect(params).toEqual(
|
expect(params).to.eql(
|
||||||
SystemInstruction.decodeCreateWithSeed(systemInstruction),
|
SystemInstruction.decodeCreateWithSeed(systemInstruction),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('createNonceAccount', () => {
|
it('createNonceAccount', () => {
|
||||||
const fromPubkey = new Account().publicKey;
|
const fromPubkey = new Account().publicKey;
|
||||||
const params = {
|
const params = {
|
||||||
fromPubkey,
|
fromPubkey,
|
||||||
@ -156,7 +154,7 @@ test('createNonceAccount', () => {
|
|||||||
const transaction = new Transaction().add(
|
const transaction = new Transaction().add(
|
||||||
SystemProgram.createNonceAccount(params),
|
SystemProgram.createNonceAccount(params),
|
||||||
);
|
);
|
||||||
expect(transaction.instructions).toHaveLength(2);
|
expect(transaction.instructions).to.have.length(2);
|
||||||
const [createInstruction, initInstruction] = transaction.instructions;
|
const [createInstruction, initInstruction] = transaction.instructions;
|
||||||
|
|
||||||
const createParams = {
|
const createParams = {
|
||||||
@ -166,7 +164,7 @@ test('createNonceAccount', () => {
|
|||||||
space: NONCE_ACCOUNT_LENGTH,
|
space: NONCE_ACCOUNT_LENGTH,
|
||||||
programId: SystemProgram.programId,
|
programId: SystemProgram.programId,
|
||||||
};
|
};
|
||||||
expect(createParams).toEqual(
|
expect(createParams).to.eql(
|
||||||
SystemInstruction.decodeCreateAccount(createInstruction),
|
SystemInstruction.decodeCreateAccount(createInstruction),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -174,12 +172,12 @@ test('createNonceAccount', () => {
|
|||||||
noncePubkey: params.noncePubkey,
|
noncePubkey: params.noncePubkey,
|
||||||
authorizedPubkey: fromPubkey,
|
authorizedPubkey: fromPubkey,
|
||||||
};
|
};
|
||||||
expect(initParams).toEqual(
|
expect(initParams).to.eql(
|
||||||
SystemInstruction.decodeNonceInitialize(initInstruction),
|
SystemInstruction.decodeNonceInitialize(initInstruction),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('createNonceAccount with seed', () => {
|
it('createNonceAccount with seed', () => {
|
||||||
const fromPubkey = new Account().publicKey;
|
const fromPubkey = new Account().publicKey;
|
||||||
const params = {
|
const params = {
|
||||||
fromPubkey,
|
fromPubkey,
|
||||||
@ -193,7 +191,7 @@ test('createNonceAccount with seed', () => {
|
|||||||
const transaction = new Transaction().add(
|
const transaction = new Transaction().add(
|
||||||
SystemProgram.createNonceAccount(params),
|
SystemProgram.createNonceAccount(params),
|
||||||
);
|
);
|
||||||
expect(transaction.instructions).toHaveLength(2);
|
expect(transaction.instructions).to.have.length(2);
|
||||||
const [createInstruction, initInstruction] = transaction.instructions;
|
const [createInstruction, initInstruction] = transaction.instructions;
|
||||||
|
|
||||||
const createParams = {
|
const createParams = {
|
||||||
@ -205,7 +203,7 @@ test('createNonceAccount with seed', () => {
|
|||||||
space: NONCE_ACCOUNT_LENGTH,
|
space: NONCE_ACCOUNT_LENGTH,
|
||||||
programId: SystemProgram.programId,
|
programId: SystemProgram.programId,
|
||||||
};
|
};
|
||||||
expect(createParams).toEqual(
|
expect(createParams).to.eql(
|
||||||
SystemInstruction.decodeCreateWithSeed(createInstruction),
|
SystemInstruction.decodeCreateWithSeed(createInstruction),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -213,21 +211,21 @@ test('createNonceAccount with seed', () => {
|
|||||||
noncePubkey: params.noncePubkey,
|
noncePubkey: params.noncePubkey,
|
||||||
authorizedPubkey: fromPubkey,
|
authorizedPubkey: fromPubkey,
|
||||||
};
|
};
|
||||||
expect(initParams).toEqual(
|
expect(initParams).to.eql(
|
||||||
SystemInstruction.decodeNonceInitialize(initInstruction),
|
SystemInstruction.decodeNonceInitialize(initInstruction),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('nonceAdvance', () => {
|
it('nonceAdvance', () => {
|
||||||
const params = {
|
const params = {
|
||||||
noncePubkey: new Account().publicKey,
|
noncePubkey: new Account().publicKey,
|
||||||
authorizedPubkey: new Account().publicKey,
|
authorizedPubkey: new Account().publicKey,
|
||||||
};
|
};
|
||||||
const instruction = SystemProgram.nonceAdvance(params);
|
const instruction = SystemProgram.nonceAdvance(params);
|
||||||
expect(params).toEqual(SystemInstruction.decodeNonceAdvance(instruction));
|
expect(params).to.eql(SystemInstruction.decodeNonceAdvance(instruction));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('nonceWithdraw', () => {
|
it('nonceWithdraw', () => {
|
||||||
const params = {
|
const params = {
|
||||||
noncePubkey: new Account().publicKey,
|
noncePubkey: new Account().publicKey,
|
||||||
authorizedPubkey: new Account().publicKey,
|
authorizedPubkey: new Account().publicKey,
|
||||||
@ -237,12 +235,12 @@ test('nonceWithdraw', () => {
|
|||||||
const transaction = new Transaction().add(
|
const transaction = new Transaction().add(
|
||||||
SystemProgram.nonceWithdraw(params),
|
SystemProgram.nonceWithdraw(params),
|
||||||
);
|
);
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [instruction] = transaction.instructions;
|
const [instruction] = transaction.instructions;
|
||||||
expect(params).toEqual(SystemInstruction.decodeNonceWithdraw(instruction));
|
expect(params).to.eql(SystemInstruction.decodeNonceWithdraw(instruction));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('nonceAuthorize', () => {
|
it('nonceAuthorize', () => {
|
||||||
const params = {
|
const params = {
|
||||||
noncePubkey: new Account().publicKey,
|
noncePubkey: new Account().publicKey,
|
||||||
authorizedPubkey: new Account().publicKey,
|
authorizedPubkey: new Account().publicKey,
|
||||||
@ -252,12 +250,12 @@ test('nonceAuthorize', () => {
|
|||||||
const transaction = new Transaction().add(
|
const transaction = new Transaction().add(
|
||||||
SystemProgram.nonceAuthorize(params),
|
SystemProgram.nonceAuthorize(params),
|
||||||
);
|
);
|
||||||
expect(transaction.instructions).toHaveLength(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
const [instruction] = transaction.instructions;
|
const [instruction] = transaction.instructions;
|
||||||
expect(params).toEqual(SystemInstruction.decodeNonceAuthorize(instruction));
|
expect(params).to.eql(SystemInstruction.decodeNonceAuthorize(instruction));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('non-SystemInstruction error', () => {
|
it('non-SystemInstruction error', () => {
|
||||||
const from = new Account();
|
const from = new Account();
|
||||||
const to = new Account();
|
const to = new Account();
|
||||||
|
|
||||||
@ -273,7 +271,7 @@ test('non-SystemInstruction error', () => {
|
|||||||
SystemInstruction.decodeInstructionType(
|
SystemInstruction.decodeInstructionType(
|
||||||
new TransactionInstruction(badProgramId),
|
new TransactionInstruction(badProgramId),
|
||||||
);
|
);
|
||||||
}).toThrow();
|
}).to.throw();
|
||||||
|
|
||||||
const stakePubkey = new Account().publicKey;
|
const stakePubkey = new Account().publicKey;
|
||||||
const authorizedPubkey = new Account().publicKey;
|
const authorizedPubkey = new Account().publicKey;
|
||||||
@ -282,28 +280,32 @@ test('non-SystemInstruction error', () => {
|
|||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
SystemInstruction.decodeInstructionType(transaction.instructions[1]);
|
SystemInstruction.decodeInstructionType(transaction.instructions[1]);
|
||||||
}).toThrow();
|
}).to.throw();
|
||||||
|
|
||||||
transaction.instructions[0].data[0] = 11;
|
transaction.instructions[0].data[0] = 11;
|
||||||
expect(() => {
|
expect(() => {
|
||||||
SystemInstruction.decodeInstructionType(transaction.instructions[0]);
|
SystemInstruction.decodeInstructionType(transaction.instructions[0]);
|
||||||
}).toThrow();
|
}).to.throw();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('live Nonce actions', async () => {
|
if (process.env.TEST_LIVE) {
|
||||||
if (mockRpcEnabled) {
|
it('live Nonce actions', async () => {
|
||||||
console.log('non-live test skipped');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const connection = new Connection(url, 'singleGossip');
|
const connection = new Connection(url, 'singleGossip');
|
||||||
const nonceAccount = new Account();
|
const nonceAccount = new Account();
|
||||||
const from = await newAccountWithLamports(connection, 2 * LAMPORTS_PER_SOL);
|
const from = new Account();
|
||||||
const to = new Account();
|
await helpers.airdrop({
|
||||||
const newAuthority = await newAccountWithLamports(
|
|
||||||
connection,
|
connection,
|
||||||
LAMPORTS_PER_SOL,
|
address: from.publicKey,
|
||||||
);
|
amount: 2 * LAMPORTS_PER_SOL,
|
||||||
|
});
|
||||||
|
|
||||||
|
const to = new Account();
|
||||||
|
const newAuthority = new Account();
|
||||||
|
await helpers.airdrop({
|
||||||
|
connection,
|
||||||
|
address: newAuthority.publicKey,
|
||||||
|
amount: LAMPORTS_PER_SOL,
|
||||||
|
});
|
||||||
|
|
||||||
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
||||||
NONCE_ACCOUNT_LENGTH,
|
NONCE_ACCOUNT_LENGTH,
|
||||||
@ -321,24 +323,24 @@ test('live Nonce actions', async () => {
|
|||||||
connection,
|
connection,
|
||||||
createNonceAccount,
|
createNonceAccount,
|
||||||
[from, nonceAccount],
|
[from, nonceAccount],
|
||||||
{commitment: 'singleGossip', preflightCommitment: 'singleGossip'},
|
{preflightCommitment: 'singleGossip'},
|
||||||
);
|
);
|
||||||
const nonceBalance = await connection.getBalance(nonceAccount.publicKey);
|
const nonceBalance = await connection.getBalance(nonceAccount.publicKey);
|
||||||
expect(nonceBalance).toEqual(minimumAmount);
|
expect(nonceBalance).to.eq(minimumAmount);
|
||||||
|
|
||||||
const nonceQuery1 = await connection.getNonce(nonceAccount.publicKey);
|
const nonceQuery1 = await connection.getNonce(nonceAccount.publicKey);
|
||||||
if (nonceQuery1 === null) {
|
if (nonceQuery1 === null) {
|
||||||
expect(nonceQuery1).not.toBeNull();
|
expect(nonceQuery1).not.to.be.null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nonceQuery2 = await connection.getNonce(nonceAccount.publicKey);
|
const nonceQuery2 = await connection.getNonce(nonceAccount.publicKey);
|
||||||
if (nonceQuery2 === null) {
|
if (nonceQuery2 === null) {
|
||||||
expect(nonceQuery2).not.toBeNull();
|
expect(nonceQuery2).not.to.be.null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(nonceQuery1.nonce).toEqual(nonceQuery2.nonce);
|
expect(nonceQuery1.nonce).to.eq(nonceQuery2.nonce);
|
||||||
|
|
||||||
// Wait for blockhash to advance
|
// Wait for blockhash to advance
|
||||||
await sleep(500);
|
await sleep(500);
|
||||||
@ -350,15 +352,14 @@ test('live Nonce actions', async () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
await sendAndConfirmTransaction(connection, advanceNonce, [from], {
|
await sendAndConfirmTransaction(connection, advanceNonce, [from], {
|
||||||
commitment: 'singleGossip',
|
|
||||||
preflightCommitment: 'singleGossip',
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
});
|
||||||
const nonceQuery3 = await connection.getNonce(nonceAccount.publicKey);
|
const nonceQuery3 = await connection.getNonce(nonceAccount.publicKey);
|
||||||
if (nonceQuery3 === null) {
|
if (nonceQuery3 === null) {
|
||||||
expect(nonceQuery3).not.toBeNull();
|
expect(nonceQuery3).not.to.be.null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
expect(nonceQuery1.nonce).not.toEqual(nonceQuery3.nonce);
|
expect(nonceQuery1.nonce).not.to.eq(nonceQuery3.nonce);
|
||||||
const nonce = nonceQuery3.nonce;
|
const nonce = nonceQuery3.nonce;
|
||||||
|
|
||||||
// Wait for blockhash to advance
|
// Wait for blockhash to advance
|
||||||
@ -372,7 +373,6 @@ test('live Nonce actions', async () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
await sendAndConfirmTransaction(connection, authorizeNonce, [from], {
|
await sendAndConfirmTransaction(connection, authorizeNonce, [from], {
|
||||||
commitment: 'singleGossip',
|
|
||||||
preflightCommitment: 'singleGossip',
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -391,12 +391,16 @@ test('live Nonce actions', async () => {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
await sendAndConfirmTransaction(connection, transfer, [from, newAuthority], {
|
await sendAndConfirmTransaction(
|
||||||
commitment: 'singleGossip',
|
connection,
|
||||||
|
transfer,
|
||||||
|
[from, newAuthority],
|
||||||
|
{
|
||||||
preflightCommitment: 'singleGossip',
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
},
|
||||||
|
);
|
||||||
const toBalance = await connection.getBalance(to.publicKey);
|
const toBalance = await connection.getBalance(to.publicKey);
|
||||||
expect(toBalance).toEqual(minimumAmount);
|
expect(toBalance).to.eq(minimumAmount);
|
||||||
|
|
||||||
// Wait for blockhash to advance
|
// Wait for blockhash to advance
|
||||||
await sleep(500);
|
await sleep(500);
|
||||||
@ -410,28 +414,29 @@ test('live Nonce actions', async () => {
|
|||||||
toPubkey: withdrawAccount.publicKey,
|
toPubkey: withdrawAccount.publicKey,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
await sendAndConfirmTransaction(connection, withdrawNonce, [newAuthority], {
|
await sendAndConfirmTransaction(
|
||||||
commitment: 'singleGossip',
|
connection,
|
||||||
|
withdrawNonce,
|
||||||
|
[newAuthority],
|
||||||
|
{
|
||||||
preflightCommitment: 'singleGossip',
|
preflightCommitment: 'singleGossip',
|
||||||
});
|
},
|
||||||
expect(await connection.getBalance(nonceAccount.publicKey)).toEqual(0);
|
);
|
||||||
|
expect(await connection.getBalance(nonceAccount.publicKey)).to.eq(0);
|
||||||
const withdrawBalance = await connection.getBalance(
|
const withdrawBalance = await connection.getBalance(
|
||||||
withdrawAccount.publicKey,
|
withdrawAccount.publicKey,
|
||||||
);
|
);
|
||||||
expect(withdrawBalance).toEqual(minimumAmount);
|
expect(withdrawBalance).to.eq(minimumAmount);
|
||||||
});
|
}).timeout(10 * 1000);
|
||||||
|
|
||||||
test('live withSeed actions', async () => {
|
|
||||||
if (mockRpcEnabled) {
|
|
||||||
console.log('non-live test skipped');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
it('live withSeed actions', async () => {
|
||||||
const connection = new Connection(url, 'singleGossip');
|
const connection = new Connection(url, 'singleGossip');
|
||||||
const baseAccount = await newAccountWithLamports(
|
const baseAccount = new Account();
|
||||||
|
await helpers.airdrop({
|
||||||
connection,
|
connection,
|
||||||
2 * LAMPORTS_PER_SOL,
|
address: baseAccount.publicKey,
|
||||||
);
|
amount: 2 * LAMPORTS_PER_SOL,
|
||||||
|
});
|
||||||
const basePubkey = baseAccount.publicKey;
|
const basePubkey = baseAccount.publicKey;
|
||||||
const seed = 'hi there';
|
const seed = 'hi there';
|
||||||
const programId = new Account().publicKey;
|
const programId = new Account().publicKey;
|
||||||
@ -463,12 +468,12 @@ test('live withSeed actions', async () => {
|
|||||||
connection,
|
connection,
|
||||||
createAccountWithSeedTransaction,
|
createAccountWithSeedTransaction,
|
||||||
[baseAccount],
|
[baseAccount],
|
||||||
{commitment: 'singleGossip', preflightCommitment: 'singleGossip'},
|
{preflightCommitment: 'singleGossip'},
|
||||||
);
|
);
|
||||||
const createAccountWithSeedBalance = await connection.getBalance(
|
const createAccountWithSeedBalance = await connection.getBalance(
|
||||||
createAccountWithSeedAddress,
|
createAccountWithSeedAddress,
|
||||||
);
|
);
|
||||||
expect(createAccountWithSeedBalance).toEqual(minimumAmount);
|
expect(createAccountWithSeedBalance).to.eq(minimumAmount);
|
||||||
|
|
||||||
// Transfer to a derived address to prep for TransferWithSeed
|
// Transfer to a derived address to prep for TransferWithSeed
|
||||||
const programId2 = new Account().publicKey;
|
const programId2 = new Account().publicKey;
|
||||||
@ -487,12 +492,12 @@ test('live withSeed actions', async () => {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
[baseAccount],
|
[baseAccount],
|
||||||
{commitment: 'singleGossip', preflightCommitment: 'singleGossip'},
|
{preflightCommitment: 'singleGossip'},
|
||||||
);
|
);
|
||||||
let transferWithSeedAddressBalance = await connection.getBalance(
|
let transferWithSeedAddressBalance = await connection.getBalance(
|
||||||
transferWithSeedAddress,
|
transferWithSeedAddress,
|
||||||
);
|
);
|
||||||
expect(transferWithSeedAddressBalance).toEqual(3 * minimumAmount);
|
expect(transferWithSeedAddressBalance).to.eq(3 * minimumAmount);
|
||||||
|
|
||||||
// Test TransferWithSeed
|
// Test TransferWithSeed
|
||||||
const programId3 = new Account();
|
const programId3 = new Account();
|
||||||
@ -516,14 +521,14 @@ test('live withSeed actions', async () => {
|
|||||||
connection,
|
connection,
|
||||||
transferWithSeedTransaction,
|
transferWithSeedTransaction,
|
||||||
[baseAccount],
|
[baseAccount],
|
||||||
{commitment: 'singleGossip', preflightCommitment: 'singleGossip'},
|
{preflightCommitment: 'singleGossip'},
|
||||||
);
|
);
|
||||||
const toBalance = await connection.getBalance(toPubkey);
|
const toBalance = await connection.getBalance(toPubkey);
|
||||||
expect(toBalance).toEqual(2 * minimumAmount);
|
expect(toBalance).to.eq(2 * minimumAmount);
|
||||||
transferWithSeedAddressBalance = await connection.getBalance(
|
transferWithSeedAddressBalance = await connection.getBalance(
|
||||||
createAccountWithSeedAddress,
|
createAccountWithSeedAddress,
|
||||||
);
|
);
|
||||||
expect(transferWithSeedAddressBalance).toEqual(minimumAmount);
|
expect(transferWithSeedAddressBalance).to.eq(minimumAmount);
|
||||||
|
|
||||||
// Test AllocateWithSeed
|
// Test AllocateWithSeed
|
||||||
const allocateWithSeedParams = {
|
const allocateWithSeedParams = {
|
||||||
@ -540,14 +545,14 @@ test('live withSeed actions', async () => {
|
|||||||
connection,
|
connection,
|
||||||
allocateWithSeedTransaction,
|
allocateWithSeedTransaction,
|
||||||
[baseAccount],
|
[baseAccount],
|
||||||
{commitment: 'singleGossip', preflightCommitment: 'singleGossip'},
|
{preflightCommitment: 'singleGossip'},
|
||||||
);
|
);
|
||||||
let account = await connection.getAccountInfo(toPubkey);
|
let account = await connection.getAccountInfo(toPubkey);
|
||||||
if (account === null) {
|
if (account === null) {
|
||||||
expect(account).not.toBeNull();
|
expect(account).not.to.be.null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
expect(account.data).toHaveLength(10);
|
expect(account.data).to.have.length(10);
|
||||||
|
|
||||||
// Test AssignWithSeed
|
// Test AssignWithSeed
|
||||||
const assignWithSeedParams = {
|
const assignWithSeedParams = {
|
||||||
@ -563,12 +568,14 @@ test('live withSeed actions', async () => {
|
|||||||
connection,
|
connection,
|
||||||
assignWithSeedTransaction,
|
assignWithSeedTransaction,
|
||||||
[baseAccount],
|
[baseAccount],
|
||||||
{commitment: 'singleGossip', preflightCommitment: 'singleGossip'},
|
{preflightCommitment: 'singleGossip'},
|
||||||
);
|
);
|
||||||
account = await connection.getAccountInfo(toPubkey);
|
account = await connection.getAccountInfo(toPubkey);
|
||||||
if (account === null) {
|
if (account === null) {
|
||||||
expect(account).not.toBeNull();
|
expect(account).not.to.be.null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
expect(account.owner).toEqual(programId3.publicKey);
|
expect(account.owner).to.eql(programId3.publicKey);
|
||||||
|
}).timeout(10 * 1000);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import {expect} from 'chai';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Account,
|
Account,
|
||||||
Connection,
|
Connection,
|
||||||
@ -6,108 +9,72 @@ import {
|
|||||||
SystemProgram,
|
SystemProgram,
|
||||||
LAMPORTS_PER_SOL,
|
LAMPORTS_PER_SOL,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
|
import {MOCK_PORT, url} from './url';
|
||||||
import {mockGetRecentBlockhash} from './mockrpc/get-recent-blockhash';
|
|
||||||
import {url} from './url';
|
|
||||||
import {mockConfirmTransaction} from './mockrpc/confirm-transaction';
|
|
||||||
|
|
||||||
if (!mockRpcEnabled) {
|
import {
|
||||||
// The default of 5 seconds is too slow for live testing sometimes
|
helpers,
|
||||||
jest.setTimeout(30000);
|
mockErrorMessage,
|
||||||
|
mockErrorResponse,
|
||||||
|
uniqueSignature,
|
||||||
|
uniqueBlockhash,
|
||||||
|
mockRpcResponse,
|
||||||
|
mockServer,
|
||||||
|
} from './mocks/rpc-http';
|
||||||
|
import {
|
||||||
|
stubRpcWebSocket,
|
||||||
|
restoreRpcWebSocket,
|
||||||
|
mockRpcMessage,
|
||||||
|
} from './mocks/rpc-websockets';
|
||||||
|
import base58 from 'bs58';
|
||||||
|
|
||||||
|
describe('Transaction Payer', () => {
|
||||||
|
let connection: Connection;
|
||||||
|
beforeEach(() => {
|
||||||
|
connection = new Connection(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!process.env.TEST_LIVE) {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockServer.start(MOCK_PORT);
|
||||||
|
stubRpcWebSocket(connection);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
mockServer.stop();
|
||||||
|
restoreRpcWebSocket(connection);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
test('transaction-payer', async () => {
|
it('transaction-payer', async () => {
|
||||||
const accountPayer = new Account();
|
const accountPayer = new Account();
|
||||||
const accountFrom = new Account();
|
const accountFrom = new Account();
|
||||||
const accountTo = new Account();
|
const accountTo = new Account();
|
||||||
const connection = new Connection(url, 'singleGossip');
|
|
||||||
|
|
||||||
mockRpc.push([
|
await helpers.airdrop({
|
||||||
url,
|
connection,
|
||||||
{
|
address: accountPayer.publicKey,
|
||||||
|
amount: LAMPORTS_PER_SOL,
|
||||||
|
});
|
||||||
|
|
||||||
|
await mockRpcResponse({
|
||||||
method: 'getMinimumBalanceForRentExemption',
|
method: 'getMinimumBalanceForRentExemption',
|
||||||
params: [0, {commitment: 'singleGossip'}],
|
params: [0],
|
||||||
},
|
value: 50,
|
||||||
{
|
});
|
||||||
error: null,
|
|
||||||
result: 50,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
|
const minimumAmount = await connection.getMinimumBalanceForRentExemption(0);
|
||||||
0,
|
|
||||||
'singleGossip',
|
|
||||||
);
|
|
||||||
|
|
||||||
mockRpc.push([
|
await helpers.airdrop({
|
||||||
url,
|
connection,
|
||||||
{
|
address: accountFrom.publicKey,
|
||||||
method: 'requestAirdrop',
|
amount: minimumAmount + 12,
|
||||||
params: [accountPayer.publicKey.toBase58(), LAMPORTS_PER_SOL],
|
});
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result:
|
|
||||||
'8WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
let signature = await connection.requestAirdrop(
|
|
||||||
accountPayer.publicKey,
|
|
||||||
LAMPORTS_PER_SOL,
|
|
||||||
);
|
|
||||||
mockConfirmTransaction(signature);
|
|
||||||
await connection.confirmTransaction(signature, 'singleGossip');
|
|
||||||
|
|
||||||
mockRpc.push([
|
await helpers.airdrop({
|
||||||
url,
|
connection,
|
||||||
{
|
address: accountTo.publicKey,
|
||||||
method: 'requestAirdrop',
|
amount: minimumAmount + 21,
|
||||||
params: [accountFrom.publicKey.toBase58(), minimumAmount + 12],
|
});
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result:
|
|
||||||
'8WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
signature = await connection.requestAirdrop(
|
|
||||||
accountFrom.publicKey,
|
|
||||||
minimumAmount + 12,
|
|
||||||
);
|
|
||||||
mockConfirmTransaction(signature);
|
|
||||||
await connection.confirmTransaction(signature, 'singleGossip');
|
|
||||||
|
|
||||||
mockRpc.push([
|
|
||||||
url,
|
|
||||||
{
|
|
||||||
method: 'requestAirdrop',
|
|
||||||
params: [accountTo.publicKey.toBase58(), minimumAmount + 21],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result:
|
|
||||||
'8WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
signature = await connection.requestAirdrop(
|
|
||||||
accountTo.publicKey,
|
|
||||||
minimumAmount + 21,
|
|
||||||
);
|
|
||||||
mockConfirmTransaction(signature);
|
|
||||||
await connection.confirmTransaction(signature, 'singleGossip');
|
|
||||||
|
|
||||||
mockGetRecentBlockhash('max');
|
|
||||||
mockRpc.push([
|
|
||||||
url,
|
|
||||||
{
|
|
||||||
method: 'sendTransaction',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result:
|
|
||||||
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const transaction = new Transaction().add(
|
const transaction = new Transaction().add(
|
||||||
SystemProgram.transfer({
|
SystemProgram.transfer({
|
||||||
@ -117,31 +84,18 @@ test('transaction-payer', async () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
signature = await connection.sendTransaction(
|
await helpers.processTransaction({
|
||||||
|
connection,
|
||||||
transaction,
|
transaction,
|
||||||
[accountPayer, accountFrom],
|
signers: [accountPayer, accountFrom],
|
||||||
{skipPreflight: true},
|
commitment: 'singleGossip',
|
||||||
);
|
});
|
||||||
|
|
||||||
mockConfirmTransaction(signature);
|
const signature = base58.encode(transaction.signature);
|
||||||
await connection.confirmTransaction(signature, 'singleGossip');
|
|
||||||
|
|
||||||
mockRpc.push([
|
await mockRpcResponse({
|
||||||
url,
|
|
||||||
{
|
|
||||||
method: 'getSignatureStatuses',
|
method: 'getSignatureStatuses',
|
||||||
params: [
|
params: [[signature]],
|
||||||
[
|
|
||||||
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result: {
|
|
||||||
context: {
|
|
||||||
slot: 11,
|
|
||||||
},
|
|
||||||
value: [
|
value: [
|
||||||
{
|
{
|
||||||
slot: 0,
|
slot: 0,
|
||||||
@ -150,58 +104,41 @@ test('transaction-payer', async () => {
|
|||||||
err: null,
|
err: null,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
withContext: true,
|
||||||
},
|
});
|
||||||
]);
|
|
||||||
const {value} = await connection.getSignatureStatus(signature);
|
const {value} = await connection.getSignatureStatus(signature);
|
||||||
if (value !== null) {
|
if (value !== null) {
|
||||||
expect(typeof value.slot).toEqual('number');
|
expect(typeof value.slot).to.eq('number');
|
||||||
expect(value.err).toBeNull();
|
expect(value.err).to.be.null;
|
||||||
} else {
|
} else {
|
||||||
expect(value).not.toBeNull();
|
expect(value).not.to.be.null;
|
||||||
}
|
}
|
||||||
|
|
||||||
mockRpc.push([
|
await mockRpcResponse({
|
||||||
url,
|
|
||||||
{
|
|
||||||
method: 'getBalance',
|
method: 'getBalance',
|
||||||
params: [accountPayer.publicKey.toBase58(), {commitment: 'singleGossip'}],
|
params: [accountPayer.publicKey.toBase58(), {commitment: 'singleGossip'}],
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result: {
|
|
||||||
context: {
|
|
||||||
slot: 11,
|
|
||||||
},
|
|
||||||
value: LAMPORTS_PER_SOL - 1,
|
value: LAMPORTS_PER_SOL - 1,
|
||||||
},
|
withContext: true,
|
||||||
},
|
});
|
||||||
]);
|
|
||||||
|
|
||||||
// accountPayer should be less than LAMPORTS_PER_SOL as it paid for the transaction
|
// accountPayer should be less than LAMPORTS_PER_SOL as it paid for the transaction
|
||||||
// (exact amount less depends on the current cluster fees)
|
// (exact amount less depends on the current cluster fees)
|
||||||
const balance = await connection.getBalance(accountPayer.publicKey);
|
const balance = await connection.getBalance(
|
||||||
expect(balance).toBeGreaterThan(0);
|
accountPayer.publicKey,
|
||||||
expect(balance).toBeLessThanOrEqual(LAMPORTS_PER_SOL);
|
'singleGossip',
|
||||||
|
);
|
||||||
|
expect(balance).to.be.greaterThan(0);
|
||||||
|
expect(balance).to.be.at.most(LAMPORTS_PER_SOL);
|
||||||
|
|
||||||
// accountFrom should have exactly 2, since it didn't pay for the transaction
|
// accountFrom should have exactly 2, since it didn't pay for the transaction
|
||||||
mockRpc.push([
|
await mockRpcResponse({
|
||||||
url,
|
|
||||||
{
|
|
||||||
method: 'getBalance',
|
method: 'getBalance',
|
||||||
params: [accountFrom.publicKey.toBase58(), {commitment: 'singleGossip'}],
|
params: [accountFrom.publicKey.toBase58(), {commitment: 'singleGossip'}],
|
||||||
},
|
|
||||||
{
|
|
||||||
error: null,
|
|
||||||
result: {
|
|
||||||
context: {
|
|
||||||
slot: 11,
|
|
||||||
},
|
|
||||||
value: minimumAmount + 2,
|
value: minimumAmount + 2,
|
||||||
},
|
withContext: true,
|
||||||
},
|
});
|
||||||
]);
|
expect(
|
||||||
expect(await connection.getBalance(accountFrom.publicKey)).toBe(
|
await connection.getBalance(accountFrom.publicKey, 'singleGossip'),
|
||||||
minimumAmount + 2,
|
).to.eq(minimumAmount + 2);
|
||||||
);
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import bs58 from 'bs58';
|
import bs58 from 'bs58';
|
||||||
|
import {Buffer} from 'buffer';
|
||||||
import nacl from 'tweetnacl';
|
import nacl from 'tweetnacl';
|
||||||
|
import {expect, use} from 'chai';
|
||||||
|
|
||||||
import {Account} from '../src/account';
|
import {Account} from '../src/account';
|
||||||
import {PublicKey} from '../src/publickey';
|
import {PublicKey} from '../src/publickey';
|
||||||
@ -9,8 +11,9 @@ import {StakeProgram} from '../src/stake-program';
|
|||||||
import {SystemProgram} from '../src/system-program';
|
import {SystemProgram} from '../src/system-program';
|
||||||
import {Message} from '../src/message';
|
import {Message} from '../src/message';
|
||||||
|
|
||||||
|
describe('Transaction', () => {
|
||||||
describe('compileMessage', () => {
|
describe('compileMessage', () => {
|
||||||
test('accountKeys are ordered', () => {
|
it('accountKeys are ordered', () => {
|
||||||
const payer = new Account();
|
const payer = new Account();
|
||||||
const account2 = new Account();
|
const account2 = new Account();
|
||||||
const account3 = new Account();
|
const account3 = new Account();
|
||||||
@ -32,12 +35,12 @@ describe('compileMessage', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const message = transaction.compileMessage();
|
const message = transaction.compileMessage();
|
||||||
expect(message.accountKeys[0].equals(payer.publicKey)).toBe(true);
|
expect(message.accountKeys[0]).to.eql(payer.publicKey);
|
||||||
expect(message.accountKeys[1].equals(account2.publicKey)).toBe(true);
|
expect(message.accountKeys[1]).to.eql(account2.publicKey);
|
||||||
expect(message.accountKeys[2].equals(account3.publicKey)).toBe(true);
|
expect(message.accountKeys[2]).to.eql(account3.publicKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('payer is first account meta', () => {
|
it('payer is first account meta', () => {
|
||||||
const payer = new Account();
|
const payer = new Account();
|
||||||
const other = new Account();
|
const other = new Account();
|
||||||
const recentBlockhash = new Account().publicKey.toBase58();
|
const recentBlockhash = new Account().publicKey.toBase58();
|
||||||
@ -52,14 +55,14 @@ describe('compileMessage', () => {
|
|||||||
|
|
||||||
transaction.sign(payer, other);
|
transaction.sign(payer, other);
|
||||||
const message = transaction.compileMessage();
|
const message = transaction.compileMessage();
|
||||||
expect(message.accountKeys[0].equals(payer.publicKey)).toBe(true);
|
expect(message.accountKeys[0]).to.eql(payer.publicKey);
|
||||||
expect(message.accountKeys[1].equals(other.publicKey)).toBe(true);
|
expect(message.accountKeys[1]).to.eql(other.publicKey);
|
||||||
expect(message.header.numRequiredSignatures).toEqual(2);
|
expect(message.header.numRequiredSignatures).to.eq(2);
|
||||||
expect(message.header.numReadonlySignedAccounts).toEqual(0);
|
expect(message.header.numReadonlySignedAccounts).to.eq(0);
|
||||||
expect(message.header.numReadonlyUnsignedAccounts).toEqual(1);
|
expect(message.header.numReadonlyUnsignedAccounts).to.eq(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('validation', () => {
|
it('validation', () => {
|
||||||
const payer = new Account();
|
const payer = new Account();
|
||||||
const other = new Account();
|
const other = new Account();
|
||||||
const recentBlockhash = new Account().publicKey.toBase58();
|
const recentBlockhash = new Account().publicKey.toBase58();
|
||||||
@ -68,13 +71,13 @@ describe('compileMessage', () => {
|
|||||||
const transaction = new Transaction();
|
const transaction = new Transaction();
|
||||||
expect(() => {
|
expect(() => {
|
||||||
transaction.compileMessage();
|
transaction.compileMessage();
|
||||||
}).toThrow('Transaction recentBlockhash required');
|
}).to.throw('Transaction recentBlockhash required');
|
||||||
|
|
||||||
transaction.recentBlockhash = recentBlockhash;
|
transaction.recentBlockhash = recentBlockhash;
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
transaction.compileMessage();
|
transaction.compileMessage();
|
||||||
}).toThrow('No instructions provided');
|
}).to.throw('No instructions provided');
|
||||||
|
|
||||||
transaction.add({
|
transaction.add({
|
||||||
keys: [
|
keys: [
|
||||||
@ -86,13 +89,13 @@ describe('compileMessage', () => {
|
|||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
transaction.compileMessage();
|
transaction.compileMessage();
|
||||||
}).toThrow('Transaction fee payer required');
|
}).to.throw('Transaction fee payer required');
|
||||||
|
|
||||||
transaction.setSigners(payer.publicKey, new Account().publicKey);
|
transaction.setSigners(payer.publicKey, new Account().publicKey);
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
transaction.compileMessage();
|
transaction.compileMessage();
|
||||||
}).toThrow('unknown signer');
|
}).to.throw('unknown signer');
|
||||||
|
|
||||||
// Expect compile to succeed with implicit fee payer from signers
|
// Expect compile to succeed with implicit fee payer from signers
|
||||||
transaction.setSigners(payer.publicKey);
|
transaction.setSigners(payer.publicKey);
|
||||||
@ -104,7 +107,7 @@ describe('compileMessage', () => {
|
|||||||
transaction.compileMessage();
|
transaction.compileMessage();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('payer is writable', () => {
|
it('payer is writable', () => {
|
||||||
const payer = new Account();
|
const payer = new Account();
|
||||||
const recentBlockhash = new Account().publicKey.toBase58();
|
const recentBlockhash = new Account().publicKey.toBase58();
|
||||||
const programId = new Account().publicKey;
|
const programId = new Account().publicKey;
|
||||||
@ -115,14 +118,14 @@ describe('compileMessage', () => {
|
|||||||
|
|
||||||
transaction.sign(payer);
|
transaction.sign(payer);
|
||||||
const message = transaction.compileMessage();
|
const message = transaction.compileMessage();
|
||||||
expect(message.accountKeys[0].equals(payer.publicKey)).toBe(true);
|
expect(message.accountKeys[0]).to.eql(payer.publicKey);
|
||||||
expect(message.header.numRequiredSignatures).toEqual(1);
|
expect(message.header.numRequiredSignatures).to.eq(1);
|
||||||
expect(message.header.numReadonlySignedAccounts).toEqual(0);
|
expect(message.header.numReadonlySignedAccounts).to.eq(0);
|
||||||
expect(message.header.numReadonlyUnsignedAccounts).toEqual(1);
|
expect(message.header.numReadonlyUnsignedAccounts).to.eq(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('partialSign', () => {
|
it('partialSign', () => {
|
||||||
const account1 = new Account();
|
const account1 = new Account();
|
||||||
const account2 = new Account();
|
const account2 = new Account();
|
||||||
const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
|
const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
|
||||||
@ -137,26 +140,26 @@ test('partialSign', () => {
|
|||||||
|
|
||||||
const partialTransaction = new Transaction({recentBlockhash}).add(transfer);
|
const partialTransaction = new Transaction({recentBlockhash}).add(transfer);
|
||||||
partialTransaction.setSigners(account1.publicKey, account2.publicKey);
|
partialTransaction.setSigners(account1.publicKey, account2.publicKey);
|
||||||
expect(partialTransaction.signatures[0].signature).toBeNull();
|
expect(partialTransaction.signatures[0].signature).to.be.null;
|
||||||
expect(partialTransaction.signatures[1].signature).toBeNull();
|
expect(partialTransaction.signatures[1].signature).to.be.null;
|
||||||
|
|
||||||
partialTransaction.partialSign(account1);
|
partialTransaction.partialSign(account1);
|
||||||
expect(partialTransaction.signatures[0].signature).not.toBeNull();
|
expect(partialTransaction.signatures[0].signature).not.to.be.null;
|
||||||
expect(partialTransaction.signatures[1].signature).toBeNull();
|
expect(partialTransaction.signatures[1].signature).to.be.null;
|
||||||
|
|
||||||
expect(() => partialTransaction.serialize()).toThrow();
|
expect(() => partialTransaction.serialize()).to.throw();
|
||||||
expect(() =>
|
expect(() =>
|
||||||
partialTransaction.serialize({requireAllSignatures: false}),
|
partialTransaction.serialize({requireAllSignatures: false}),
|
||||||
).not.toThrow();
|
).not.to.throw();
|
||||||
|
|
||||||
partialTransaction.partialSign(account2);
|
partialTransaction.partialSign(account2);
|
||||||
|
|
||||||
expect(partialTransaction.signatures[0].signature).not.toBeNull();
|
expect(partialTransaction.signatures[0].signature).not.to.be.null;
|
||||||
expect(partialTransaction.signatures[1].signature).not.toBeNull();
|
expect(partialTransaction.signatures[1].signature).not.to.be.null;
|
||||||
|
|
||||||
expect(() => partialTransaction.serialize()).not.toThrow();
|
expect(() => partialTransaction.serialize()).not.to.throw();
|
||||||
|
|
||||||
expect(partialTransaction).toEqual(transaction);
|
expect(partialTransaction).to.eql(transaction);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
partialTransaction.signatures[0].signature != null /* <-- pacify flow */
|
partialTransaction.signatures[0].signature != null /* <-- pacify flow */
|
||||||
@ -164,13 +167,13 @@ test('partialSign', () => {
|
|||||||
partialTransaction.signatures[0].signature[0] = 0;
|
partialTransaction.signatures[0].signature[0] = 0;
|
||||||
expect(() =>
|
expect(() =>
|
||||||
partialTransaction.serialize({requireAllSignatures: false}),
|
partialTransaction.serialize({requireAllSignatures: false}),
|
||||||
).toThrow();
|
).to.throw();
|
||||||
expect(() =>
|
expect(() =>
|
||||||
partialTransaction.serialize({
|
partialTransaction.serialize({
|
||||||
verifySignatures: false,
|
verifySignatures: false,
|
||||||
requireAllSignatures: false,
|
requireAllSignatures: false,
|
||||||
}),
|
}),
|
||||||
).not.toThrow();
|
).not.to.throw();
|
||||||
} else {
|
} else {
|
||||||
throw new Error('unreachable');
|
throw new Error('unreachable');
|
||||||
}
|
}
|
||||||
@ -183,7 +186,7 @@ describe('dedupe', () => {
|
|||||||
const recentBlockhash = new Account().publicKey.toBase58();
|
const recentBlockhash = new Account().publicKey.toBase58();
|
||||||
const programId = new Account().publicKey;
|
const programId = new Account().publicKey;
|
||||||
|
|
||||||
test('setSigners', () => {
|
it('setSigners', () => {
|
||||||
const transaction = new Transaction({recentBlockhash}).add({
|
const transaction = new Transaction({recentBlockhash}).add({
|
||||||
keys: [
|
keys: [
|
||||||
{pubkey: duplicate1.publicKey, isSigner: true, isWritable: true},
|
{pubkey: duplicate1.publicKey, isSigner: true, isWritable: true},
|
||||||
@ -199,21 +202,19 @@ describe('dedupe', () => {
|
|||||||
duplicate2.publicKey,
|
duplicate2.publicKey,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(transaction.signatures.length).toEqual(1);
|
expect(transaction.signatures).to.have.length(1);
|
||||||
expect(transaction.signatures[0].publicKey.equals(payer.publicKey)).toBe(
|
expect(transaction.signatures[0].publicKey).to.eql(payer.publicKey);
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
const message = transaction.compileMessage();
|
const message = transaction.compileMessage();
|
||||||
expect(message.accountKeys[0].equals(payer.publicKey)).toBe(true);
|
expect(message.accountKeys[0]).to.eql(payer.publicKey);
|
||||||
expect(message.header.numRequiredSignatures).toEqual(1);
|
expect(message.header.numRequiredSignatures).to.eq(1);
|
||||||
expect(message.header.numReadonlySignedAccounts).toEqual(0);
|
expect(message.header.numReadonlySignedAccounts).to.eq(0);
|
||||||
expect(message.header.numReadonlyUnsignedAccounts).toEqual(1);
|
expect(message.header.numReadonlyUnsignedAccounts).to.eq(1);
|
||||||
|
|
||||||
transaction.signatures;
|
transaction.signatures;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('sign', () => {
|
it('sign', () => {
|
||||||
const transaction = new Transaction({recentBlockhash}).add({
|
const transaction = new Transaction({recentBlockhash}).add({
|
||||||
keys: [
|
keys: [
|
||||||
{pubkey: duplicate1.publicKey, isSigner: true, isWritable: true},
|
{pubkey: duplicate1.publicKey, isSigner: true, isWritable: true},
|
||||||
@ -225,22 +226,20 @@ describe('dedupe', () => {
|
|||||||
|
|
||||||
transaction.sign(payer, duplicate1, duplicate2);
|
transaction.sign(payer, duplicate1, duplicate2);
|
||||||
|
|
||||||
expect(transaction.signatures.length).toEqual(1);
|
expect(transaction.signatures).to.have.length(1);
|
||||||
expect(transaction.signatures[0].publicKey.equals(payer.publicKey)).toBe(
|
expect(transaction.signatures[0].publicKey).to.eql(payer.publicKey);
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
const message = transaction.compileMessage();
|
const message = transaction.compileMessage();
|
||||||
expect(message.accountKeys[0].equals(payer.publicKey)).toBe(true);
|
expect(message.accountKeys[0]).to.eql(payer.publicKey);
|
||||||
expect(message.header.numRequiredSignatures).toEqual(1);
|
expect(message.header.numRequiredSignatures).to.eq(1);
|
||||||
expect(message.header.numReadonlySignedAccounts).toEqual(0);
|
expect(message.header.numReadonlySignedAccounts).to.eq(0);
|
||||||
expect(message.header.numReadonlyUnsignedAccounts).toEqual(1);
|
expect(message.header.numReadonlyUnsignedAccounts).to.eq(1);
|
||||||
|
|
||||||
transaction.signatures;
|
transaction.signatures;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('transfer signatures', () => {
|
it('transfer signatures', () => {
|
||||||
const account1 = new Account();
|
const account1 = new Account();
|
||||||
const account2 = new Account();
|
const account2 = new Account();
|
||||||
const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
|
const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
|
||||||
@ -267,10 +266,10 @@ test('transfer signatures', () => {
|
|||||||
signatures: orgTransaction.signatures,
|
signatures: orgTransaction.signatures,
|
||||||
}).add(transfer1, transfer2);
|
}).add(transfer1, transfer2);
|
||||||
|
|
||||||
expect(newTransaction).toEqual(orgTransaction);
|
expect(newTransaction).to.eql(orgTransaction);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('dedup signatures', () => {
|
it('dedup signatures', () => {
|
||||||
const account1 = new Account();
|
const account1 = new Account();
|
||||||
const account2 = new Account();
|
const account2 = new Account();
|
||||||
const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
|
const recentBlockhash = account1.publicKey.toBase58(); // Fake recentBlockhash
|
||||||
@ -292,7 +291,7 @@ test('dedup signatures', () => {
|
|||||||
orgTransaction.sign(account1);
|
orgTransaction.sign(account1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('use nonce', () => {
|
it('use nonce', () => {
|
||||||
const account1 = new Account();
|
const account1 = new Account();
|
||||||
const account2 = new Account();
|
const account2 = new Account();
|
||||||
const nonceAccount = new Account();
|
const nonceAccount = new Account();
|
||||||
@ -318,12 +317,12 @@ test('use nonce', () => {
|
|||||||
let expectedData = Buffer.alloc(4);
|
let expectedData = Buffer.alloc(4);
|
||||||
expectedData.writeInt32LE(4, 0);
|
expectedData.writeInt32LE(4, 0);
|
||||||
|
|
||||||
expect(transferTransaction.instructions).toHaveLength(2);
|
expect(transferTransaction.instructions).to.have.length(2);
|
||||||
expect(transferTransaction.instructions[0].programId).toEqual(
|
expect(transferTransaction.instructions[0].programId).to.eql(
|
||||||
SystemProgram.programId,
|
SystemProgram.programId,
|
||||||
);
|
);
|
||||||
expect(transferTransaction.instructions[0].data).toEqual(expectedData);
|
expect(transferTransaction.instructions[0].data).to.eql(expectedData);
|
||||||
expect(transferTransaction.recentBlockhash).toEqual(nonce);
|
expect(transferTransaction.recentBlockhash).to.eq(nonce);
|
||||||
|
|
||||||
const stakeAccount = new Account();
|
const stakeAccount = new Account();
|
||||||
const voteAccount = new Account();
|
const voteAccount = new Account();
|
||||||
@ -336,15 +335,15 @@ test('use nonce', () => {
|
|||||||
);
|
);
|
||||||
stakeTransaction.sign(account1);
|
stakeTransaction.sign(account1);
|
||||||
|
|
||||||
expect(stakeTransaction.instructions).toHaveLength(2);
|
expect(stakeTransaction.instructions).to.have.length(2);
|
||||||
expect(stakeTransaction.instructions[0].programId).toEqual(
|
expect(stakeTransaction.instructions[0].programId).to.eql(
|
||||||
SystemProgram.programId,
|
SystemProgram.programId,
|
||||||
);
|
);
|
||||||
expect(stakeTransaction.instructions[0].data).toEqual(expectedData);
|
expect(stakeTransaction.instructions[0].data).to.eql(expectedData);
|
||||||
expect(stakeTransaction.recentBlockhash).toEqual(nonce);
|
expect(stakeTransaction.recentBlockhash).to.eq(nonce);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('parse wire format and serialize', () => {
|
it('parse wire format and serialize', () => {
|
||||||
const keypair = nacl.sign.keyPair.fromSeed(
|
const keypair = nacl.sign.keyPair.fromSeed(
|
||||||
Uint8Array.from(Array(32).fill(8)),
|
Uint8Array.from(Array(32).fill(8)),
|
||||||
);
|
);
|
||||||
@ -370,11 +369,11 @@ test('parse wire format and serialize', () => {
|
|||||||
);
|
);
|
||||||
const tx = Transaction.from(wireTransaction);
|
const tx = Transaction.from(wireTransaction);
|
||||||
|
|
||||||
expect(tx).toEqual(expectedTransaction);
|
expect(tx).to.eql(expectedTransaction);
|
||||||
expect(wireTransaction).toEqual(expectedTransaction.serialize());
|
expect(wireTransaction).to.eql(expectedTransaction.serialize());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('populate transaction', () => {
|
it('populate transaction', () => {
|
||||||
const recentBlockhash = new PublicKey(1).toString();
|
const recentBlockhash = new PublicKey(1).toString();
|
||||||
const message = {
|
const message = {
|
||||||
accountKeys: [
|
accountKeys: [
|
||||||
@ -405,12 +404,12 @@ test('populate transaction', () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const transaction = Transaction.populate(new Message(message), signatures);
|
const transaction = Transaction.populate(new Message(message), signatures);
|
||||||
expect(transaction.instructions.length).toEqual(1);
|
expect(transaction.instructions).to.have.length(1);
|
||||||
expect(transaction.signatures.length).toEqual(2);
|
expect(transaction.signatures).to.have.length(2);
|
||||||
expect(transaction.recentBlockhash).toEqual(recentBlockhash);
|
expect(transaction.recentBlockhash).to.eq(recentBlockhash);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('serialize unsigned transaction', () => {
|
it('serialize unsigned transaction', () => {
|
||||||
const keypair = nacl.sign.keyPair.fromSeed(
|
const keypair = nacl.sign.keyPair.fromSeed(
|
||||||
Uint8Array.from(Array(32).fill(8)),
|
Uint8Array.from(Array(32).fill(8)),
|
||||||
);
|
);
|
||||||
@ -424,26 +423,28 @@ test('serialize unsigned transaction', () => {
|
|||||||
toPubkey: recipient,
|
toPubkey: recipient,
|
||||||
lamports: 49,
|
lamports: 49,
|
||||||
});
|
});
|
||||||
const expectedTransaction = new Transaction({recentBlockhash}).add(transfer);
|
const expectedTransaction = new Transaction({recentBlockhash}).add(
|
||||||
|
transfer,
|
||||||
|
);
|
||||||
|
|
||||||
// Empty signature array fails.
|
// Empty signature array fails.
|
||||||
expect(expectedTransaction.signatures.length).toBe(0);
|
expect(expectedTransaction.signatures).to.have.length(0);
|
||||||
expect(() => {
|
expect(() => {
|
||||||
expectedTransaction.serialize();
|
expectedTransaction.serialize();
|
||||||
}).toThrow('Transaction fee payer required');
|
}).to.throw('Transaction fee payer required');
|
||||||
expect(() => {
|
expect(() => {
|
||||||
expectedTransaction.serialize({verifySignatures: false});
|
expectedTransaction.serialize({verifySignatures: false});
|
||||||
}).toThrow('Transaction fee payer required');
|
}).to.throw('Transaction fee payer required');
|
||||||
expect(() => {
|
expect(() => {
|
||||||
expectedTransaction.serializeMessage();
|
expectedTransaction.serializeMessage();
|
||||||
}).toThrow('Transaction fee payer required');
|
}).to.throw('Transaction fee payer required');
|
||||||
|
|
||||||
expectedTransaction.feePayer = sender.publicKey;
|
expectedTransaction.feePayer = sender.publicKey;
|
||||||
|
|
||||||
// Transactions with missing signatures will fail sigverify.
|
// Transactions with missing signatures will fail sigverify.
|
||||||
expect(() => {
|
expect(() => {
|
||||||
expectedTransaction.serialize();
|
expectedTransaction.serialize();
|
||||||
}).toThrow('Signature verification failed');
|
}).to.throw('Signature verification failed');
|
||||||
|
|
||||||
// Serializing without signatures is allowed if sigverify disabled.
|
// Serializing without signatures is allowed if sigverify disabled.
|
||||||
expectedTransaction.serialize({verifySignatures: false});
|
expectedTransaction.serialize({verifySignatures: false});
|
||||||
@ -453,12 +454,12 @@ test('serialize unsigned transaction', () => {
|
|||||||
|
|
||||||
expectedTransaction.feePayer = null;
|
expectedTransaction.feePayer = null;
|
||||||
expectedTransaction.setSigners(sender.publicKey);
|
expectedTransaction.setSigners(sender.publicKey);
|
||||||
expect(expectedTransaction.signatures.length).toBe(1);
|
expect(expectedTransaction.signatures).to.have.length(1);
|
||||||
|
|
||||||
// Transactions with missing signatures will fail sigverify.
|
// Transactions with missing signatures will fail sigverify.
|
||||||
expect(() => {
|
expect(() => {
|
||||||
expectedTransaction.serialize();
|
expectedTransaction.serialize();
|
||||||
}).toThrow('Signature verification failed');
|
}).to.throw('Signature verification failed');
|
||||||
|
|
||||||
// Serializing without signatures is allowed if sigverify disabled.
|
// Serializing without signatures is allowed if sigverify disabled.
|
||||||
expectedTransaction.serialize({verifySignatures: false});
|
expectedTransaction.serialize({verifySignatures: false});
|
||||||
@ -474,13 +475,13 @@ test('serialize unsigned transaction', () => {
|
|||||||
'AAAAMQAAAAAAAAA=',
|
'AAAAMQAAAAAAAAA=',
|
||||||
'base64',
|
'base64',
|
||||||
);
|
);
|
||||||
expect(
|
expect(expectedTransaction.serialize({requireAllSignatures: false})).to.eql(
|
||||||
expectedTransaction.serialize({requireAllSignatures: false}),
|
expectedSerializationWithNoSignatures,
|
||||||
).toStrictEqual(expectedSerializationWithNoSignatures);
|
);
|
||||||
|
|
||||||
// Properly signed transaction succeeds
|
// Properly signed transaction succeeds
|
||||||
expectedTransaction.partialSign(sender);
|
expectedTransaction.partialSign(sender);
|
||||||
expect(expectedTransaction.signatures.length).toBe(1);
|
expect(expectedTransaction.signatures).to.have.length(1);
|
||||||
const expectedSerialization = Buffer.from(
|
const expectedSerialization = Buffer.from(
|
||||||
'AVuErQHaXv0SG0/PchunfxHKt8wMRfMZzqV0tkC5qO6owYxWU2v871AoWywGoFQr4z+q/7mE8lIufNl/' +
|
'AVuErQHaXv0SG0/PchunfxHKt8wMRfMZzqV0tkC5qO6owYxWU2v871AoWywGoFQr4z+q/7mE8lIufNl/' +
|
||||||
'kxj+nQ0BAAEDE5j2LG0aRXxRumpLXz29L2n8qTIWIY3ImX5Ba9F9k8r9Q5/Mtmcn8onFxt47xKj+XdXX' +
|
'kxj+nQ0BAAEDE5j2LG0aRXxRumpLXz29L2n8qTIWIY3ImX5Ba9F9k8r9Q5/Mtmcn8onFxt47xKj+XdXX' +
|
||||||
@ -488,11 +489,11 @@ test('serialize unsigned transaction', () => {
|
|||||||
'ROug7bEsbx0xxuDkqEvwUusBAgIAAQwCAAAAMQAAAAAAAAA=',
|
'ROug7bEsbx0xxuDkqEvwUusBAgIAAQwCAAAAMQAAAAAAAAA=',
|
||||||
'base64',
|
'base64',
|
||||||
);
|
);
|
||||||
expect(expectedTransaction.serialize()).toStrictEqual(expectedSerialization);
|
expect(expectedTransaction.serialize()).to.eql(expectedSerialization);
|
||||||
expect(expectedTransaction.signatures.length).toBe(1);
|
expect(expectedTransaction.signatures).to.have.length(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('deprecated - externally signed stake delegate', () => {
|
it('deprecated - externally signed stake delegate', () => {
|
||||||
const from_keypair = nacl.sign.keyPair.fromSeed(
|
const from_keypair = nacl.sign.keyPair.fromSeed(
|
||||||
Uint8Array.from(Array(32).fill(1)),
|
Uint8Array.from(Array(32).fill(1)),
|
||||||
);
|
);
|
||||||
@ -511,10 +512,10 @@ test('deprecated - externally signed stake delegate', () => {
|
|||||||
const tx_bytes = tx.serializeMessage();
|
const tx_bytes = tx.serializeMessage();
|
||||||
const signature = nacl.sign.detached(tx_bytes, from.secretKey);
|
const signature = nacl.sign.detached(tx_bytes, from.secretKey);
|
||||||
tx.addSignature(from.publicKey, signature);
|
tx.addSignature(from.publicKey, signature);
|
||||||
expect(tx.verifySignatures()).toBe(true);
|
expect(tx.verifySignatures()).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('externally signed stake delegate', () => {
|
it('externally signed stake delegate', () => {
|
||||||
const from_keypair = nacl.sign.keyPair.fromSeed(
|
const from_keypair = nacl.sign.keyPair.fromSeed(
|
||||||
Uint8Array.from(Array(32).fill(1)),
|
Uint8Array.from(Array(32).fill(1)),
|
||||||
);
|
);
|
||||||
@ -533,5 +534,6 @@ test('externally signed stake delegate', () => {
|
|||||||
const tx_bytes = tx.serializeMessage();
|
const tx_bytes = tx.serializeMessage();
|
||||||
const signature = nacl.sign.detached(tx_bytes, from.secretKey);
|
const signature = nacl.sign.detached(tx_bytes, from.secretKey);
|
||||||
tx.addSignature(from.publicKey, signature);
|
tx.addSignature(from.publicKey, signature);
|
||||||
expect(tx.verifySignatures()).toBe(true);
|
expect(tx.verifySignatures()).to.be.true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,10 @@
|
|||||||
* The connection url to use when running unit tests against a live cluster
|
* The connection url to use when running unit tests against a live cluster
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const url = 'http://localhost:8899/';
|
export const MOCK_PORT = 9999;
|
||||||
|
export const url = process.env.TEST_LIVE
|
||||||
|
? 'http://localhost:8899/'
|
||||||
|
: 'http://localhost:9999/';
|
||||||
|
|
||||||
//export const url = 'https://devnet.solana.com/';
|
//export const url = 'https://devnet.solana.com/';
|
||||||
//export const url = 'http://devnet.solana.com/';
|
//export const url = 'http://devnet.solana.com/';
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
import {Buffer} from 'buffer';
|
||||||
|
import {expect} from 'chai';
|
||||||
import nacl from 'tweetnacl';
|
import nacl from 'tweetnacl';
|
||||||
|
|
||||||
import {PublicKey} from '../src/publickey';
|
import {PublicKey} from '../src/publickey';
|
||||||
import {ValidatorInfo} from '../src/validator-info';
|
import {ValidatorInfo} from '../src/validator-info';
|
||||||
|
|
||||||
test('from config account data', () => {
|
describe('ValidatorInfo', () => {
|
||||||
|
it('from config account data', () => {
|
||||||
const keypair = nacl.sign.keyPair.fromSeed(
|
const keypair = nacl.sign.keyPair.fromSeed(
|
||||||
Uint8Array.from(Array(32).fill(8)),
|
Uint8Array.from(Array(32).fill(8)),
|
||||||
);
|
);
|
||||||
@ -32,5 +35,6 @@ test('from config account data', () => {
|
|||||||
);
|
);
|
||||||
const info = ValidatorInfo.fromConfigData(configData);
|
const info = ValidatorInfo.fromConfigData(configData);
|
||||||
|
|
||||||
expect(info).toEqual(expectedValidatorInfo);
|
expect(info).to.eql(expectedValidatorInfo);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,68 +1,68 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import bs58 from 'bs58';
|
import bs58 from 'bs58';
|
||||||
|
import {Buffer} from 'buffer';
|
||||||
|
import {expect, use} from 'chai';
|
||||||
|
import chaiAsPromised from 'chai-as-promised';
|
||||||
|
|
||||||
import {Connection} from '../src';
|
import {Connection} from '../src';
|
||||||
import {url} from './url';
|
import {url} from './url';
|
||||||
import {mockRpcEnabled} from './__mocks__/node-fetch';
|
|
||||||
import {sleep} from '../src/util/sleep';
|
import {sleep} from '../src/util/sleep';
|
||||||
|
|
||||||
describe('websocket', () => {
|
use(chaiAsPromised);
|
||||||
if (mockRpcEnabled) {
|
|
||||||
test('no-op', () => {});
|
|
||||||
console.log('non-live test skipped');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (process.env.TEST_LIVE) {
|
||||||
|
describe('websocket', () => {
|
||||||
const connection = new Connection(url);
|
const connection = new Connection(url);
|
||||||
|
|
||||||
test('connect and disconnect', async () => {
|
it('connect and disconnect', async () => {
|
||||||
const testSignature = bs58.encode(Buffer.alloc(64));
|
const testSignature = bs58.encode(Buffer.alloc(64));
|
||||||
const id = connection.onSignature(testSignature, () => {});
|
const id = connection.onSignature(testSignature, () => {});
|
||||||
|
|
||||||
// wait for websocket to connect
|
// wait for websocket to connect
|
||||||
await sleep(100);
|
await sleep(100);
|
||||||
expect(connection._rpcWebSocketConnected).toBe(true);
|
expect(connection._rpcWebSocketConnected).to.be.true;
|
||||||
expect(connection._rpcWebSocketHeartbeat).not.toBe(null);
|
expect(connection._rpcWebSocketHeartbeat).not.to.eq(null);
|
||||||
|
|
||||||
// test if socket is open
|
// test if socket is open
|
||||||
await connection._rpcWebSocket.notify('ping');
|
await connection._rpcWebSocket.notify('ping');
|
||||||
|
|
||||||
await connection.removeSignatureListener(id);
|
await connection.removeSignatureListener(id);
|
||||||
expect(connection._rpcWebSocketConnected).toBe(false);
|
expect(connection._rpcWebSocketConnected).to.eq(false);
|
||||||
expect(connection._rpcWebSocketHeartbeat).not.toBe(null);
|
expect(connection._rpcWebSocketHeartbeat).not.to.eq(null);
|
||||||
expect(connection._rpcWebSocketIdleTimeout).not.toBe(null);
|
expect(connection._rpcWebSocketIdleTimeout).not.to.eq(null);
|
||||||
|
|
||||||
// wait for websocket to disconnect
|
// wait for websocket to disconnect
|
||||||
await sleep(1100);
|
await sleep(1100);
|
||||||
expect(connection._rpcWebSocketConnected).toBe(false);
|
expect(connection._rpcWebSocketConnected).to.eq(false);
|
||||||
expect(connection._rpcWebSocketHeartbeat).toBe(null);
|
expect(connection._rpcWebSocketHeartbeat).to.eq(null);
|
||||||
expect(connection._rpcWebSocketIdleTimeout).toBe(null);
|
expect(connection._rpcWebSocketIdleTimeout).to.eq(null);
|
||||||
|
|
||||||
// test if socket is closed
|
// test if socket is closed
|
||||||
await expect(connection._rpcWebSocket.notify('ping')).rejects.toThrow(
|
await expect(connection._rpcWebSocket.notify('ping')).to.be.rejectedWith(
|
||||||
'socket not ready',
|
'socket not ready',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('idle timeout', async () => {
|
it('idle timeout', async () => {
|
||||||
const testSignature = bs58.encode(Buffer.alloc(64));
|
const testSignature = bs58.encode(Buffer.alloc(64));
|
||||||
const id = connection.onSignature(testSignature, () => {});
|
const id = connection.onSignature(testSignature, () => {});
|
||||||
|
|
||||||
// wait for websocket to connect
|
// wait for websocket to connect
|
||||||
await sleep(100);
|
await sleep(100);
|
||||||
expect(connection._rpcWebSocketIdleTimeout).toBe(null);
|
expect(connection._rpcWebSocketIdleTimeout).to.eq(null);
|
||||||
|
|
||||||
await connection.removeSignatureListener(id);
|
await connection.removeSignatureListener(id);
|
||||||
expect(connection._rpcWebSocketIdleTimeout).not.toBe(null);
|
expect(connection._rpcWebSocketIdleTimeout).not.to.eq(null);
|
||||||
|
|
||||||
const nextId = connection.onSignature(testSignature, () => {});
|
const nextId = connection.onSignature(testSignature, () => {});
|
||||||
expect(connection._rpcWebSocketIdleTimeout).toBe(null);
|
expect(connection._rpcWebSocketIdleTimeout).to.eq(null);
|
||||||
|
|
||||||
await connection.removeSignatureListener(nextId);
|
await connection.removeSignatureListener(nextId);
|
||||||
expect(connection._rpcWebSocketIdleTimeout).not.toBe(null);
|
expect(connection._rpcWebSocketIdleTimeout).not.to.eq(null);
|
||||||
|
|
||||||
// wait for websocket to disconnect
|
// wait for websocket to disconnect
|
||||||
await sleep(1100);
|
await sleep(1100);
|
||||||
expect(connection._rpcWebSocketIdleTimeout).toBe(null);
|
expect(connection._rpcWebSocketIdleTimeout).to.eq(null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user