mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 10:35:50 +00:00
379 lines
10 KiB
JavaScript
379 lines
10 KiB
JavaScript
let assert = require('assert');
|
|
let _ = require('lodash');
|
|
let async = require('async');
|
|
let testutils = require('./testutils');
|
|
let config = testutils.init_config();
|
|
let accounts = require('./testconfig').accounts;
|
|
let Amount = require('ripple-lib').Amount;
|
|
let Transaction = require('ripple-lib').Transaction;
|
|
|
|
suite('MultiSign', function() {
|
|
let $ = {};
|
|
let opts = {};
|
|
|
|
setup(function(done) {
|
|
testutils.build_setup(opts).call($, done);
|
|
});
|
|
|
|
setup(function(done) {
|
|
$.remote.local_signing = false;
|
|
testutils.create_accounts(
|
|
$.remote,
|
|
'root',
|
|
Amount.from_human('1000 XRP'),
|
|
['alice', 'bob', 'carol'],
|
|
done);
|
|
});
|
|
|
|
teardown(function(done) {
|
|
testutils.build_teardown().call($, done);
|
|
});
|
|
|
|
function getAliceSequence(callback) {
|
|
return $.remote.account('alice')._transactionManager._nextSequence;
|
|
}
|
|
|
|
test('remote signing', function(done) {
|
|
async.series([
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('SignerListSet', {
|
|
account: accounts.alice.account,
|
|
signers: [
|
|
{account: accounts.bob.account, weight: 1},
|
|
{account: accounts.carol.account, weight: 2 }
|
|
],
|
|
signerQuorum: 3
|
|
});
|
|
|
|
testutils.submit_transaction(tx, callback);
|
|
},
|
|
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('AccountSet', {account: accounts.alice.account});
|
|
tx.setFee(100);
|
|
tx.setSequence(getAliceSequence());
|
|
tx.setLastLedgerSequenceOffset(5);
|
|
|
|
let mTx = Transaction.from_json(tx.getMultiSigningJson());
|
|
|
|
[accounts.bob, accounts.carol].forEach(account => {
|
|
let signer = mTx.multiSign( account.account, account.secret);
|
|
assert(signer.Account);
|
|
assert(signer.SigningPubKey);
|
|
assert(signer.TxnSignature);
|
|
|
|
tx.addMultiSigner(signer);
|
|
});
|
|
|
|
tx.once('submitted', function(res) {
|
|
assert.strictEqual(res.engine_result, 'tesSUCCESS');
|
|
assert.deepEqual(res.tx_json.Signers, tx.getMultiSigners());
|
|
callback();
|
|
});
|
|
|
|
tx.submit();
|
|
}
|
|
], done);
|
|
});
|
|
|
|
test('local signing', function(done) {
|
|
$.remote.local_signing = true;
|
|
|
|
async.series([
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('SignerListSet', {
|
|
account: accounts.alice.account,
|
|
signers: [
|
|
{account: accounts.bob.account, weight: 1},
|
|
{account: accounts.carol.account, weight: 2 }
|
|
],
|
|
signerQuorum: 3
|
|
});
|
|
|
|
testutils.submit_transaction(tx, callback);
|
|
},
|
|
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('AccountSet', {account: accounts.alice.account});
|
|
tx.setFee(100);
|
|
tx.setSequence(getAliceSequence());
|
|
tx.setLastLedgerSequenceOffset(5);
|
|
|
|
let mTx = Transaction.from_json(tx.getMultiSigningJson());
|
|
|
|
[accounts.bob, accounts.carol].forEach(account => {
|
|
let signer = mTx.multiSign( account.account, account.secret);
|
|
assert(signer.Account);
|
|
assert(signer.SigningPubKey);
|
|
assert(signer.TxnSignature);
|
|
|
|
tx.addMultiSigner(signer);
|
|
});
|
|
|
|
tx.once('submitted', function(res) {
|
|
assert.strictEqual(res.engine_result, 'tesSUCCESS');
|
|
assert.deepEqual(res.tx_json.Signers, tx.getMultiSigners());
|
|
callback();
|
|
});
|
|
|
|
tx.submit();
|
|
}
|
|
], done);
|
|
});
|
|
|
|
test('No multi-signers specified for account', function(done) {
|
|
async.series([
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('AccountSet', {account: accounts.alice.account});
|
|
tx.setFee(100);
|
|
tx.setSequence(getAliceSequence());
|
|
tx.setLastLedgerSequenceOffset(5);
|
|
|
|
let mTx = Transaction.from_json(tx.getMultiSigningJson());
|
|
|
|
let signer = mTx.multiSign(accounts.bob.account, accounts.bob.secret);
|
|
assert(signer.Account);
|
|
assert(signer.SigningPubKey);
|
|
assert(signer.TxnSignature);
|
|
|
|
tx.addMultiSigner(signer);
|
|
|
|
tx.once('submitted', function(res) {
|
|
assert.strictEqual(res.engine_result, 'tefNOT_MULTI_SIGNING');
|
|
callback();
|
|
});
|
|
|
|
tx.submit();
|
|
}
|
|
], done);
|
|
});
|
|
|
|
test('Attempt to use unspecified signer', function(done) {
|
|
async.series([
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('SignerListSet', {
|
|
account: accounts.alice.account,
|
|
signers: [
|
|
{account: accounts.bob.account, weight: 1},
|
|
],
|
|
signerQuorum: 1
|
|
});
|
|
|
|
testutils.submit_transaction(tx, callback);
|
|
},
|
|
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('AccountSet', {account: accounts.alice.account});
|
|
tx.setFee(100);
|
|
tx.setSequence(getAliceSequence());
|
|
tx.setLastLedgerSequenceOffset(5);
|
|
|
|
let mTx = Transaction.from_json(tx.getMultiSigningJson());
|
|
|
|
let signer = mTx.multiSign(accounts.carol.account, accounts.carol.secret);
|
|
assert(signer.Account);
|
|
assert(signer.SigningPubKey);
|
|
assert(signer.TxnSignature);
|
|
|
|
tx.addMultiSigner(signer);
|
|
|
|
tx.once('submitted', function(res) {
|
|
assert.strictEqual(res.engine_result, 'tefBAD_SIGNATURE');
|
|
callback();
|
|
});
|
|
|
|
tx.submit();
|
|
}
|
|
], done);
|
|
});
|
|
|
|
test('Unmet quorum', function(done) {
|
|
async.series([
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('SignerListSet', {
|
|
account: accounts.alice.account,
|
|
signers: [
|
|
{account: accounts.bob.account, weight: 1},
|
|
{account: accounts.carol.account, weight: 1}
|
|
],
|
|
signerQuorum: 2
|
|
});
|
|
|
|
testutils.submit_transaction(tx, callback);
|
|
},
|
|
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('AccountSet', {account: accounts.alice.account});
|
|
tx.setFee(100);
|
|
tx.setSequence(getAliceSequence());
|
|
tx.setLastLedgerSequenceOffset(5);
|
|
|
|
let mTx = Transaction.from_json(tx.getMultiSigningJson());
|
|
|
|
let signer = mTx.multiSign(accounts.bob.account, accounts.bob.secret);
|
|
assert(signer.Account);
|
|
assert(signer.SigningPubKey);
|
|
assert(signer.TxnSignature);
|
|
|
|
tx.addMultiSigner(signer);
|
|
|
|
tx.once('submitted', function(res) {
|
|
assert.strictEqual(res.engine_result, 'tefBAD_QUORUM');
|
|
callback();
|
|
});
|
|
|
|
tx.submit();
|
|
}
|
|
], done);
|
|
});
|
|
|
|
test('Unreachable quorum', function(done) {
|
|
async.series([
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('SignerListSet', {
|
|
account: accounts.alice.account,
|
|
signers: [
|
|
{account: accounts.bob.account, weight: 1},
|
|
],
|
|
signerQuorum: 2
|
|
});
|
|
|
|
tx.once('submitted', function(res) {
|
|
assert.strictEqual(res.engine_result, 'temBAD_QUORUM');
|
|
callback();
|
|
});
|
|
tx.submit();
|
|
},
|
|
], done);
|
|
});
|
|
|
|
test('Invalid signature -- modified tx_json', function(done) {
|
|
async.series([
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('SignerListSet', {
|
|
account: accounts.alice.account,
|
|
signers: [
|
|
{account: accounts.bob.account, weight: 1},
|
|
],
|
|
signerQuorum: 1
|
|
});
|
|
|
|
testutils.submit_transaction(tx, callback);
|
|
},
|
|
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('AccountSet', {account: accounts.alice.account});
|
|
tx.setFee(100);
|
|
tx.setSequence(getAliceSequence());
|
|
tx.setLastLedgerSequenceOffset(5);
|
|
|
|
let mTx = Transaction.from_json(tx.getMultiSigningJson());
|
|
// Tamper with transaction data prior to multi-signing
|
|
mTx.setSequence(getAliceSequence() + 1);
|
|
|
|
let signer = mTx.multiSign(accounts.bob.account, accounts.bob.secret);
|
|
assert(signer.Account);
|
|
assert(signer.SigningPubKey);
|
|
assert(signer.TxnSignature);
|
|
|
|
tx.addMultiSigner(signer);
|
|
|
|
tx.once('submitted', function(res) {
|
|
assert(res.error)
|
|
assert.strictEqual(res.remote.error_message, 'Invalid signature.')
|
|
callback();
|
|
});
|
|
|
|
tx.submit();
|
|
}
|
|
], done);
|
|
});
|
|
|
|
test('Invalid signature -- malformed signer', function(done) {
|
|
async.series([
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('SignerListSet', {
|
|
account: accounts.alice.account,
|
|
signers: [
|
|
{account: accounts.bob.account, weight: 1},
|
|
],
|
|
signerQuorum: 1
|
|
});
|
|
|
|
testutils.submit_transaction(tx, callback);
|
|
},
|
|
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('AccountSet', {account: accounts.alice.account});
|
|
tx.setFee(100);
|
|
tx.setSequence(getAliceSequence());
|
|
tx.setLastLedgerSequenceOffset(5);
|
|
|
|
let mTx = Transaction.from_json(tx.getMultiSigningJson());
|
|
|
|
let signer = mTx.multiSign(accounts.bob.account, accounts.bob.secret);
|
|
// Tamper with signer after multi-signing
|
|
signer.Account = accounts.carol.account;
|
|
|
|
assert(signer.Account);
|
|
assert(signer.SigningPubKey);
|
|
assert(signer.TxnSignature);
|
|
|
|
tx.addMultiSigner(signer);
|
|
|
|
tx.once('submitted', function(res) {
|
|
assert(res.error)
|
|
assert.strictEqual(res.remote.error_message, 'Invalid signature.')
|
|
callback();
|
|
});
|
|
|
|
tx.submit();
|
|
}
|
|
], done);
|
|
});
|
|
|
|
test('Invalid signature -- SigningPubKey non-empty', function(done) {
|
|
async.series([
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('SignerListSet', {
|
|
account: accounts.alice.account,
|
|
signers: [
|
|
{account: accounts.bob.account, weight: 1},
|
|
],
|
|
signerQuorum: 1
|
|
});
|
|
|
|
testutils.submit_transaction(tx, callback);
|
|
},
|
|
|
|
function(callback) {
|
|
let tx = $.remote.createTransaction('AccountSet', {account: accounts.alice.account});
|
|
tx.setFee(100);
|
|
tx.setSequence(getAliceSequence());
|
|
tx.setLastLedgerSequenceOffset(5);
|
|
|
|
let mTx = Transaction.from_json(tx.getMultiSigningJson());
|
|
|
|
let signer = mTx.multiSign(accounts.bob.account, accounts.bob.secret);
|
|
assert(signer.Account);
|
|
assert(signer.SigningPubKey);
|
|
assert(signer.TxnSignature);
|
|
|
|
tx.addMultiSigner(signer);
|
|
|
|
tx.once('presubmit', function(res) {
|
|
// SigningPubKey must be empty
|
|
tx.setSigningPubKey(tx.getSigningPubKey());
|
|
});
|
|
tx.once('submitted', function(res) {
|
|
assert(res.error);
|
|
assert.strictEqual(res.remote.error, 'invalidParams');
|
|
callback();
|
|
});
|
|
|
|
tx.submit();
|
|
}
|
|
], done);
|
|
});
|
|
});
|