PHP WebShell
Текущая директория: /opt/BitGoJS/modules/sdk-coin-cspr/test/unit/lib
Просмотр файла: transaction.ts
import assert from 'assert';
import should from 'should';
import { coins } from '@bitgo/statics';
import { CLString, DeployUtil, CLPublicKey as PublicKey } from 'casper-js-sdk';
import { Transaction } from '../../../src/lib/transaction';
import * as testData from '../../fixtures/resources';
import { KeyPair, TransactionBuilderFactory } from '../../../src/lib';
import { DEFAULT_CHAIN_NAMES, OWNER_PREFIX } from '../../../src/lib/constants';
import {
getTransferAmount,
getTransferDestinationAddress,
getTransferId,
isValidTransactionSignature,
verifySignature,
} from '../../../src/lib/utils';
describe('Cspr Transaction', () => {
const coin = coins.get('tcspr');
const factory = new TransactionBuilderFactory(coin);
const owner1Address = new KeyPair({ pub: testData.ACCOUNT_1.publicKey }).getAddress();
const owner2Address = new KeyPair({ pub: testData.ACCOUNT_2.publicKey }).getAddress();
const owner3Address = new KeyPair({ pub: testData.ACCOUNT_3.publicKey }).getAddress();
const sourceAddress = new KeyPair({ pub: testData.ROOT_ACCOUNT.publicKey }).getAddress();
const getTransaction = (): Transaction => {
return new Transaction(coin);
};
const getWalletInitTransaction = async (): Promise<Transaction> => {
const txBuilder = factory.getWalletInitializationBuilder();
txBuilder.fee(testData.FEE);
txBuilder.owner(owner1Address);
txBuilder.owner(owner2Address);
txBuilder.owner(owner3Address);
txBuilder.source({ address: sourceAddress });
txBuilder.sign({ key: testData.ROOT_ACCOUNT.privateKey });
return (await txBuilder.build()) as Transaction;
};
const getWalletInitTransactionUsignExtendedKey = async (): Promise<Transaction> => {
const txBuilder = factory.getWalletInitializationBuilder();
txBuilder.fee(testData.FEE);
txBuilder.owner(owner1Address);
txBuilder.owner(owner2Address);
txBuilder.owner(owner3Address);
txBuilder.source({ address: sourceAddress });
txBuilder.sign({ key: testData.ROOT_ACCOUNT.xPrivateKey });
return (await txBuilder.build()) as Transaction;
};
const getTransferTransaction = async (): Promise<Transaction> => {
const txBuilder = factory.getTransferBuilder();
txBuilder.fee({ gasLimit: testData.FEE.gasLimit, gasPrice: testData.FEE.gasPrice });
txBuilder.source({ address: sourceAddress });
txBuilder.to(owner2Address);
txBuilder.amount(testData.MIN_MOTES_AMOUNT);
txBuilder.transferId(255);
return (await txBuilder.build()) as Transaction;
};
// Creates a deploy instance, required to test signing.
const getTransferDeploy = (): DeployUtil.Deploy | undefined => {
const gasPrice = testData.FEE.gasPrice ? parseInt(testData.FEE.gasPrice, 10) : undefined;
const sourcePublicKey = PublicKey.fromHex(testData.SECP256K1_PREFIX + testData.ACCOUNT_1.publicKey);
const deployParams = new DeployUtil.DeployParams(sourcePublicKey, DEFAULT_CHAIN_NAMES.testnet, gasPrice);
const session = DeployUtil.ExecutableDeployItem.newTransfer(1, sourcePublicKey, undefined, 123);
const payment = DeployUtil.standardPayment(parseInt(testData.FEE.gasLimit, 10));
return DeployUtil.makeDeploy(deployParams, session, payment);
};
it('should throw empty transaction', () => {
const tx = getTransaction();
assert.throws(() => {
tx.toJson();
});
assert.throws(() => {
tx.toBroadcastFormat();
});
});
describe('should sign if transaction is', () => {
it('valid', async () => {
const tx = getTransaction();
const transferDeploy = getTransferDeploy();
if (transferDeploy) {
tx.casperTx = transferDeploy;
}
const keypair = new KeyPair({ prv: testData.ACCOUNT_1.privateKey });
should.doesNotThrow(() => tx.sign(keypair));
should.equal(tx.casperTx.approvals[0].signer, testData.SECP256K1_PREFIX + testData.ACCOUNT_1.publicKey);
should.equal(
isValidTransactionSignature(
tx.casperTx.approvals[0].signature,
tx.casperTx.hash,
Buffer.from(tx.casperTx.header.account.value()).toString('hex')
),
true
);
should.doesNotThrow(() =>
verifySignature(
tx.casperTx.approvals[0].signature,
tx.casperTx.hash,
Buffer.from(tx.casperTx.header.account.value()).toString('hex')
)
);
});
it('valid using extended key', async () => {
const tx = getTransaction();
const transferDeploy = getTransferDeploy();
if (transferDeploy) {
tx.casperTx = transferDeploy;
}
const keypair = new KeyPair({ prv: testData.ACCOUNT_1.xPrivateKey });
should.doesNotThrow(() => tx.sign(keypair));
should.equal(tx.casperTx.approvals[0].signer, testData.SECP256K1_PREFIX + testData.ACCOUNT_1.publicKey);
should.equal(
isValidTransactionSignature(
tx.casperTx.approvals[0].signature,
tx.casperTx.hash,
Buffer.from(tx.casperTx.header.account.value()).toString('hex')
),
true
);
should.doesNotThrow(() =>
verifySignature(
tx.casperTx.approvals[0].signature,
tx.casperTx.hash,
Buffer.from(tx.casperTx.header.account.value()).toString('hex')
)
);
});
it('multiple valid', async () => {
const tx = getTransaction();
const transferDeploy = getTransferDeploy();
if (transferDeploy) {
tx.casperTx = transferDeploy;
}
const keypair = new KeyPair({ prv: testData.ACCOUNT_1.privateKey });
const keypair2 = new KeyPair({ prv: testData.ACCOUNT_2.privateKey });
should.doesNotThrow(() => tx.sign(keypair));
should.equal(tx.casperTx.approvals[0].signer, testData.SECP256K1_PREFIX + testData.ACCOUNT_1.publicKey);
should.equal(
isValidTransactionSignature(tx.casperTx.approvals[0].signature, tx.casperTx.hash, testData.ACCOUNT_1.publicKey),
true
);
should.doesNotThrow(() =>
verifySignature(tx.casperTx.approvals[0].signature, tx.casperTx.hash, testData.ACCOUNT_1.publicKey)
);
should.doesNotThrow(() => tx.sign(keypair2));
should.equal(tx.casperTx.approvals[0].signer, testData.SECP256K1_PREFIX + testData.ACCOUNT_1.publicKey);
should.equal(tx.casperTx.approvals[1].signer, testData.SECP256K1_PREFIX + testData.ACCOUNT_2.publicKey);
should.equal(
isValidTransactionSignature(tx.casperTx.approvals[0].signature, tx.casperTx.hash, testData.ACCOUNT_1.publicKey),
true
);
should.equal(
isValidTransactionSignature(tx.casperTx.approvals[1].signature, tx.casperTx.hash, testData.ACCOUNT_2.publicKey),
true
);
should.doesNotThrow(() =>
verifySignature(tx.casperTx.approvals[0].signature, tx.casperTx.hash, testData.ACCOUNT_1.publicKey)
);
should.doesNotThrow(() =>
verifySignature(tx.casperTx.approvals[1].signature, tx.casperTx.hash, testData.ACCOUNT_2.publicKey)
);
});
it('multiple valid using extended keys', async () => {
const tx = getTransaction();
const transferDeploy = getTransferDeploy();
if (transferDeploy) {
tx.casperTx = transferDeploy;
}
const keypair = new KeyPair({ prv: testData.ACCOUNT_1.xPrivateKey });
const keypair2 = new KeyPair({ prv: testData.ACCOUNT_2.xPrivateKey });
should.doesNotThrow(() => tx.sign(keypair));
should.equal(tx.casperTx.approvals[0].signer, testData.SECP256K1_PREFIX + testData.ACCOUNT_1.publicKey);
should.equal(
isValidTransactionSignature(tx.casperTx.approvals[0].signature, tx.casperTx.hash, testData.ACCOUNT_1.publicKey),
true
);
should.doesNotThrow(() =>
verifySignature(tx.casperTx.approvals[0].signature, tx.casperTx.hash, testData.ACCOUNT_1.publicKey)
);
should.doesNotThrow(() => tx.sign(keypair2));
should.equal(tx.casperTx.approvals[0].signer, testData.SECP256K1_PREFIX + testData.ACCOUNT_1.publicKey);
should.equal(tx.casperTx.approvals[1].signer, testData.SECP256K1_PREFIX + testData.ACCOUNT_2.publicKey);
should.equal(
isValidTransactionSignature(tx.casperTx.approvals[0].signature, tx.casperTx.hash, testData.ACCOUNT_1.publicKey),
true
);
should.equal(
isValidTransactionSignature(tx.casperTx.approvals[1].signature, tx.casperTx.hash, testData.ACCOUNT_2.publicKey),
true
);
should.doesNotThrow(() =>
verifySignature(tx.casperTx.approvals[0].signature, tx.casperTx.hash, testData.ACCOUNT_1.publicKey)
);
should.doesNotThrow(() =>
verifySignature(tx.casperTx.approvals[1].signature, tx.casperTx.hash, testData.ACCOUNT_2.publicKey)
);
});
it('multiple valid using one extended key', async () => {
const tx = getTransaction();
const transferDeploy = getTransferDeploy();
if (transferDeploy) {
tx.casperTx = transferDeploy;
}
const keypair = new KeyPair({ prv: testData.ACCOUNT_1.xPrivateKey });
const keypair2 = new KeyPair({ prv: testData.ACCOUNT_2.privateKey });
should.doesNotThrow(() => tx.sign(keypair));
should.equal(tx.casperTx.approvals[0].signer, testData.SECP256K1_PREFIX + testData.ACCOUNT_1.publicKey);
should.equal(
isValidTransactionSignature(tx.casperTx.approvals[0].signature, tx.casperTx.hash, testData.ACCOUNT_1.publicKey),
true
);
should.doesNotThrow(() =>
verifySignature(tx.casperTx.approvals[0].signature, tx.casperTx.hash, testData.ACCOUNT_1.publicKey)
);
should.doesNotThrow(() => tx.sign(keypair2));
should.equal(tx.casperTx.approvals[0].signer, testData.SECP256K1_PREFIX + testData.ACCOUNT_1.publicKey);
should.equal(tx.casperTx.approvals[1].signer, testData.SECP256K1_PREFIX + testData.ACCOUNT_2.publicKey);
should.equal(
isValidTransactionSignature(tx.casperTx.approvals[0].signature, tx.casperTx.hash, testData.ACCOUNT_1.publicKey),
true
);
should.equal(
isValidTransactionSignature(tx.casperTx.approvals[1].signature, tx.casperTx.hash, testData.ACCOUNT_2.publicKey),
true
);
should.doesNotThrow(() =>
verifySignature(tx.casperTx.approvals[0].signature, tx.casperTx.hash, testData.ACCOUNT_1.publicKey)
);
should.doesNotThrow(() =>
verifySignature(tx.casperTx.approvals[1].signature, tx.casperTx.hash, testData.ACCOUNT_2.publicKey)
);
});
});
describe('should reject sign if transaction signer is', () => {
it('invalid private key', function () {
const tx = getTransaction();
assert.throws(() => tx.sign(testData.INVALID_KEYPAIR_PRV));
});
it('public key', function () {
const tx = getTransaction();
const keypair = new KeyPair({ pub: testData.ACCOUNT_1.publicKey });
assert.throws(
() => tx.sign(keypair),
(e: Error) => e.message === testData.ERROR_MISSING_PRIVATE_KEY
);
});
it('public extended key', function () {
const tx = getTransaction();
const keypair = new KeyPair({ pub: testData.ACCOUNT_1.xPublicKey });
assert.throws(
() => tx.sign(keypair),
(e: Error) => e.message === testData.ERROR_MISSING_PRIVATE_KEY
);
});
});
describe('should return encoded tx', function () {
it('wallet initialization', async function () {
const walletInitTx = await getWalletInitTransaction();
const encodedTx = walletInitTx.toBroadcastFormat();
const walletInitJsonTx = JSON.parse(encodedTx);
const argName = 0;
const argValue = 1;
const owner0 = 0;
const owner1 = 1;
const owner2 = 2;
const ownersValues = new Map();
[owner0, owner1, owner2].forEach((index) => {
ownersValues.set(
OWNER_PREFIX + index,
(walletInitTx.casperTx.session.getArgByName(OWNER_PREFIX + index) as CLString).value()
);
});
const jsonOwnerArgs = walletInitJsonTx['deploy']['session']['ModuleBytes']['args'].filter((arg) =>
ownersValues.has(arg[argName])
);
jsonOwnerArgs.length.should.equal(ownersValues.size);
jsonOwnerArgs.forEach((arg) => {
arg[argValue]['parsed'].should.be.equal(ownersValues.get(arg[argName]));
});
});
it('wallet initialization using extended key', async function () {
const walletInitTx = await getWalletInitTransactionUsignExtendedKey();
const encodedTx = walletInitTx.toBroadcastFormat();
const walletInitJsonTx = JSON.parse(encodedTx);
const argName = 0;
const argValue = 1;
const owner0 = 0;
const owner1 = 1;
const owner2 = 2;
const ownersValues = new Map();
[owner0, owner1, owner2].forEach((index) => {
ownersValues.set(
OWNER_PREFIX + index,
(walletInitTx.casperTx.session.getArgByName(OWNER_PREFIX + index) as CLString).value()
);
});
const jsonOwnerArgs = walletInitJsonTx['deploy']['session']['ModuleBytes']['args'].filter((arg) =>
ownersValues.has(arg[argName])
);
jsonOwnerArgs.length.should.equal(ownersValues.size);
jsonOwnerArgs.forEach((arg) => {
arg[argValue]['parsed'].should.be.equal(ownersValues.get(arg[argName]));
});
});
it('transfer', async function () {
const transferTx = await getTransferTransaction();
const encodedTx = transferTx.toBroadcastFormat();
const transferJsonTx = JSON.parse(encodedTx);
const argName = 0;
const argValue = 1;
const transferValues = new Map();
transferValues.set('amount', getTransferAmount(transferTx.casperTx.session));
transferValues.set('to_address', getTransferDestinationAddress(transferTx.casperTx.session));
const transferId = getTransferId(transferTx.casperTx.session);
if (transferId !== undefined) {
transferValues.set('id', transferId.toString());
}
const jsonOwnerArgs = transferJsonTx['deploy']['session']['Transfer']['args'].filter((arg) =>
transferValues.has(arg[argName])
);
jsonOwnerArgs.length.should.equal(transferValues.size);
jsonOwnerArgs.forEach((arg) => {
arg[argValue]['parsed'].should.be.equal(transferValues.get(arg[argName]));
});
});
// TODO STLX-1174: get and decode encoded transaction
it('valid sign', function (done) {
done();
});
});
});
Выполнить команду
Для локальной разработки. Не используйте в интернете!