Skip to content

Commit

Permalink
Add Transaction.signingData
Browse files Browse the repository at this point in the history
  • Loading branch information
sublimator committed Jun 23, 2015
1 parent 0be70d6 commit bb91810
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 76 deletions.
21 changes: 16 additions & 5 deletions src/core/hashprefixes.js
@@ -1,3 +1,10 @@
'use strict';

// TODO: move in helpers from serializedtypes to utils
function toBytes(n) {
return [n >>> 24, (n >>> 16) & 0xff, (n >>> 8) & 0xff, n & 0xff];
}

/**
* Prefix for hashing functions.
*
Expand All @@ -12,14 +19,18 @@
*/

// transaction plus signature to give transaction ID
exports.HASH_TX_ID = 0x54584E00; // 'TXN'
exports.HASH_TX_ID = 0x54584E00; // 'TXN'
// transaction plus metadata
exports.HASH_TX_NODE = 0x534E4400; // 'TND'
exports.HASH_TX_NODE = 0x534E4400; // 'TND'
// inner node in tree
exports.HASH_INNER_NODE = 0x4D494E00; // 'MIN'
exports.HASH_INNER_NODE = 0x4D494E00; // 'MIN'
// leaf node in tree
exports.HASH_LEAF_NODE = 0x4D4C4E00; // 'MLN'
exports.HASH_LEAF_NODE = 0x4D4C4E00; // 'MLN'
// inner transaction to sign
exports.HASH_TX_SIGN = 0x53545800; // 'STX'
exports.HASH_TX_SIGN = 0x53545800; // 'STX'
// inner transaction to sign (TESTNET)
exports.HASH_TX_SIGN_TESTNET = 0x73747800; // 'stx'

Object.keys(exports).forEach(function(k) {
exports[k + '_BYTES'] = toBytes(exports[k]);
});
104 changes: 53 additions & 51 deletions src/core/serializedobject.js
Expand Up @@ -49,58 +49,10 @@ function SerializedObject(buf) {
}
this.pointer = 0;
}

SerializedObject.from_json = function(obj_) {
// Create a copy of the object so we don't modify it
const obj = extend(true, {}, obj_);


SerializedObject.from_json = function(obj) {
const so = new SerializedObject();
let typedef;

if (typeof obj.TransactionType === 'number') {
obj.TransactionType = SerializedObject.lookup_type_tx(obj.TransactionType);
if (!obj.TransactionType) {
throw new Error('Transaction type ID is invalid.');
}
}

if (typeof obj.LedgerEntryType === 'number') {
obj.LedgerEntryType = SerializedObject.lookup_type_le(obj.LedgerEntryType);

if (!obj.LedgerEntryType) {
throw new Error('LedgerEntryType ID is invalid.');
}
}

if (typeof obj.TransactionType === 'string') {
typedef = binformat.tx[obj.TransactionType];
if (!Array.isArray(typedef)) {
throw new Error('Transaction type is invalid');
}

typedef = typedef.slice();
obj.TransactionType = typedef.shift();
} else if (typeof obj.LedgerEntryType === 'string') {
typedef = binformat.ledger[obj.LedgerEntryType];

if (!Array.isArray(typedef)) {
throw new Error('LedgerEntryType is invalid');
}

typedef = typedef.slice();
obj.LedgerEntryType = typedef.shift();

} else if (typeof obj.AffectedNodes === 'object') {
typedef = binformat.metadata;
} else {
throw new Error('Object to be serialized must contain either' +
' TransactionType, LedgerEntryType or AffectedNodes.');
}

// ND: This from_*json* seems a reasonable place to put validation of `json`
SerializedObject.check_fields(typedef, obj);
so.serialize(typedef, obj);

so.parse_json(obj);
return so;
};

Expand Down Expand Up @@ -154,6 +106,56 @@ SerializedObject.check_fields = function(typedef, obj) {
throw new Error(errorMessage);
};

SerializedObject.prototype.parse_json = function(obj_) {
const so = this;
// Create a copy of the object so we don't modify it
const obj = extend(true, {}, obj_);
let typedef;

if (typeof obj.TransactionType === 'number') {
obj.TransactionType = SerializedObject.lookup_type_tx(obj.TransactionType);
if (!obj.TransactionType) {
throw new Error('Transaction type ID is invalid.');
}
}

if (typeof obj.LedgerEntryType === 'number') {
obj.LedgerEntryType = SerializedObject.lookup_type_le(obj.LedgerEntryType);

if (!obj.LedgerEntryType) {
throw new Error('LedgerEntryType ID is invalid.');
}
}

if (typeof obj.TransactionType === 'string') {
typedef = binformat.tx[obj.TransactionType];
if (!Array.isArray(typedef)) {
throw new Error('Transaction type is invalid');
}

typedef = typedef.slice();
obj.TransactionType = typedef.shift();
} else if (typeof obj.LedgerEntryType === 'string') {
typedef = binformat.ledger[obj.LedgerEntryType];

if (!Array.isArray(typedef)) {
throw new Error('LedgerEntryType is invalid');
}

typedef = typedef.slice();
obj.LedgerEntryType = typedef.shift();

} else if (typeof obj.AffectedNodes === 'object') {
typedef = binformat.metadata;
} else {
throw new Error('Object to be serialized must contain either' +
' TransactionType, LedgerEntryType or AffectedNodes.');
}

SerializedObject.check_fields(typedef, obj);
so.serialize(typedef, obj);
};

SerializedObject.prototype.append = function(bytes_) {
const bytes = bytes_ instanceof SerializedObject ? bytes_.buffer : bytes_;

Expand Down
21 changes: 14 additions & 7 deletions src/core/transaction.js
Expand Up @@ -274,7 +274,7 @@ Transaction.prototype.getManager = function(account_) {
return undefined;
}

let account = account_ || this.tx_json.Account;
const account = account_ || this.tx_json.Account;
return this.remote.account(account)._transactionManager;
};

Expand All @@ -290,7 +290,7 @@ Transaction.prototype._accountSecret = function(account_) {
return undefined;
}

let account = account_ || this.tx_json.Account;
const account = account_ || this.tx_json.Account;
return this.remote.secrets[account];
};

Expand Down Expand Up @@ -326,7 +326,7 @@ Transaction.prototype._computeFee = function() {
const fees = [ ];

for (let i = 0; i < servers.length; i++) {
let server = servers[i];
const server = servers[i];
if (server.isConnected()) {
fees.push(Number(server._computeFee(this._getFeeUnits())));
}
Expand Down Expand Up @@ -435,6 +435,13 @@ Transaction.prototype.signingHash = function(testnet) {
return this.hash(testnet ? 'HASH_TX_SIGN_TESTNET' : 'HASH_TX_SIGN');
};

Transaction.prototype.signingData = function() {
const so = new SerializedObject();
so.append(hashprefixes.HASH_TX_SIGN_BYTES);
so.parse_json(this.tx_json);
return so;
};

Transaction.prototype.hash = function(prefix_, asUINT256, serialized) {
let prefix;

Expand Down Expand Up @@ -770,7 +777,7 @@ Transaction.prototype.addMemo = function(options_) {
const memo = {};
const memoRegex = Transaction.MEMO_REGEX;
let memoType = options.memoType;
let memoFormat = options.memoFormat;
const memoFormat = options.memoFormat;
let memoData = options.memoData;

if (memoType) {
Expand Down Expand Up @@ -918,7 +925,7 @@ Transaction.prototype.transferRate = function(rate) {
// }
/* eslint-enable max-len */

let transferRate = rate;
const transferRate = rate;

if (transferRate === 0) {
// Clear TransferRate
Expand Down Expand Up @@ -1323,7 +1330,7 @@ Transaction.prototype.setExpiration = function(expiration) {
// throw new Error('TransactionType must be OfferCreate to use Expiration');
// }

let timeOffset = expiration instanceof Date
const timeOffset = expiration instanceof Date
? expiration.getTime()
: expiration;

Expand Down Expand Up @@ -1433,7 +1440,7 @@ Transaction.prototype.abort = function() {

Transaction.prototype.getSummary =
Transaction.prototype.summary = function() {
let txSummary = {
const txSummary = {
tx_json: this.tx_json,
clientID: this._clientID,
submittedIDs: this.submittedIDs,
Expand Down
45 changes: 32 additions & 13 deletions test/transaction-test.js
Expand Up @@ -553,19 +553,38 @@ describe('Transaction', function() {
done();
});

it('Get signing hash', function(done) {
const transaction = new Transaction();
transaction._secret = 'sh2pTicynUEG46jjR4EoexHcQEoij';
transaction.tx_json.SigningPubKey = '021FED5FD081CE5C4356431267D04C6E2167E4112C897D5E10335D4E22B4DA49ED';
transaction.tx_json.Account = 'rMWwx3Ma16HnqSd4H6saPisihX9aKpXxHJ';
transaction.tx_json.Flags = 0;
transaction.tx_json.Fee = 10;
transaction.tx_json.Sequence = 1;
transaction.tx_json.TransactionType = 'AccountSet';
describe('signing', function() {
const tx_json = {
SigningPubKey: '021FED5FD081CE5C4356431267D04C6E2167E4112C897D5E10335D4E22B4DA49ED',
Account: 'rMWwx3Ma16HnqSd4H6saPisihX9aKpXxHJ',
Flags: 0,
Fee: 10,
Sequence: 1,
TransactionType: 'AccountSet'
};

assert.strictEqual(transaction.signingHash(), 'D1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE');
const expectedSigningHash =
'D1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE';

done();
it('Get signing hash', function() {
const transaction = Transaction.from_json(tx_json);
transaction._secret = 'sh2pTicynUEG46jjR4EoexHcQEoij';
assert.strictEqual(transaction.signingHash(), expectedSigningHash);
});

it('Get signing data', function() {
const tx = Transaction.from_json(tx_json);
const data = tx.signingData();

assert.strictEqual(data.hash().to_json(),
expectedSigningHash);

assert.strictEqual(data.to_hex(),
('535458001200032200000000240000000168400000000000000' +
'A7321021FED5FD081CE5C4356431267D04C6E2167E4112C897D' +
'5E10335D4E22B4DA49ED8114E0E6E281CA324AEE034B2BB8AC9' +
'7BA1ACA95A068'));
});
});

it('Get hash - no prefix', function(done) {
Expand Down Expand Up @@ -1959,7 +1978,7 @@ describe('Transaction', function() {
});

it('Get min ledger', function() {
let queue = new TransactionQueue();
const queue = new TransactionQueue();

// Randomized submit indexes
[
Expand All @@ -1975,7 +1994,7 @@ describe('Transaction', function() {
543305
]
.forEach(function(index) {
let tx = new Transaction();
const tx = new Transaction();
tx.initialSubmitIndex = index;
queue.push(tx);
});
Expand Down

0 comments on commit bb91810

Please sign in to comment.